I'd like to reuse a functionality several times in a single class. This functionality relies on a private variable:
trait Address {
private $address;
public function getAddress() {
return $this->address;
}
public function setAddress($address) {
$this->address = $address;
}
}
The only way I've found to use the trait twice, is the following:
class User {
use Address {
getAddress as getHomeAddress;
setAddress as setHomeAddress;
getAddress as getWorkAddress;
setAddress as setWorkAddress;
}
}
The problem is, by doing this, the private variable $address
is shared across the different methods, and the code will not work as expected:
$user = new User();
$user->setHomeAddress('21 Jump Street');
echo $user->getWorkAddress(); // 21 Jump Street
Is there a solution to really use the trait twice, while not sharing its private variables?
Traits can have properties and methods with private and protected visibility too. You can access them like they belong to class itself. There is no difference.
Variables are private to protect the state of your objects - in object-oriented programming terms, this is called encapsulation.
Traits can define static variables, static methods and static properties. Note: As of PHP 8.1. 0, calling a static method, or accessing a static property directly on a trait is deprecated.
Use the __setter (__set) function to set value(s) to your private variable inside a the class, and when the value is needed, use the __getter (__get) function to return the values.
Declaring a trait with use
will not create an instance of that trait. Traits are basically just code that is copy and pasted into the using class. The as
will only create an Alias for that method, e.g. it will add something like
public function getHomeAddress()
{
return $this->getAddress();
}
to your User class. But it will still only be that one trait. There will not be two different $address
properties, but just one.
You could make the methods private and then delegate any public calls to it via __call
by switch/casing on the method name and using an array for address, e.g.
trait Address {
private $address = array();
private function getAddress($type) {
return $this->address[$type];
}
private function setAddress($type, $address) {
$this->address[$type] = $address;
}
public function __call($method, $args) {
switch ($method) {
case 'setHomeAddress':
return $this->setAddress('home', $args[0]);
// more cases …
}
}
}
But that is just a can of worms.
In other words, you cannot sanely do what you are trying to do with traits. Either use two different traits. Or use good old aggregation and add concrete proxy methods.
i may be a little late for the party, but the behavior you are trying to create is not something that should be covered by a trait, but by simple object composition.
<?php
class Adddress {
private $street;
private $number;
public function __construct(string $street, ?string $number) {}
public function street() : string {}
public function number() : string {}
}
class User {
private $homeAddress;
private $workAddress;
public function getHomeAddress() : Address {}
public function setHomeAddress(Address $homeAddress) : self {}
public function getWorkAddress() : Address {}
public function setWorkAddress(Address $workAddress) : self {}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With