如何使变量私有于特征?

2022-08-30 22:08:44

我想在单个类中多次重用一个功能。此功能依赖于私有变量:

trait Address {
    private $address;

    public function getAddress() {
        return $this->address;
    }

    public function setAddress($address) {
        $this->address = $address;
    }
}

我发现两次使用该特征的唯一方法是:

class User  {
    use Address {
        getAddress as getHomeAddress;
        setAddress as setHomeAddress;

        getAddress as getWorkAddress;            
        setAddress as setWorkAddress;
    }
}

问题是,通过执行此操作,私有变量在不同的方法之间共享,并且代码将无法按预期工作:$address

$user = new User();
$user->setHomeAddress('21 Jump Street');
echo $user->getWorkAddress(); // 21 Jump Street

有没有一个解决方案可以真正使用两次该特征,同时不共享其私有变量?


答案 1

声明一个 trait with 不会创建该特征的实例。特征基本上只是复制并粘贴到 using 类中的代码。只会为该方法创建一个别名,例如,它将添加类似的东西useas

public function getHomeAddress()
{
    return $this->getAddress();
}

添加到您的用户类。但它仍然只是一个特征。不会有两个不同的属性,而只有一个。$address

您可以将这些方法设为私有,然后通过切换/大小写方法名称并使用数组作为地址来委派任何公共调用,例如__call

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 …
        }
    }
}

但那只是一罐蠕虫。

换句话说,你不能理智地做你想用特质做的事情。要么使用两种不同的特征。或者使用良好的旧聚合并添加具体的代理方法。


答案 2

我可能有点晚了,但你试图创造的行为不是应该被一种特质所覆盖的东西,而是通过简单的对象组合来覆盖的。

<?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 {}
}

推荐