Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP特性通用和单独(单独)属性范围_Php_Oop_Properties_Scope_Traits - Fatal编程技术网

PHP特性通用和单独(单独)属性范围

PHP特性通用和单独(单独)属性范围,php,oop,properties,scope,traits,Php,Oop,Properties,Scope,Traits,在traits中定义的方法可以访问属性的公共范围,如在同一对象中定义的方法,这是很有用的。但是,有没有办法让两个trait可以使用相同的属性名称,但每个属性都在不同的范围内,这样setTwo()就不会覆盖trait one的$this->data,反之亦然 例如: <?php namespace one; trait one { public function setOne($data) { $this->data = $data; }

在traits中定义的方法可以访问属性的公共范围,如在同一对象中定义的方法,这是很有用的。但是,有没有办法让两个trait可以使用相同的属性名称,但每个属性都在不同的范围内,这样
setTwo()
就不会覆盖
trait one
$this->data
,反之亦然

例如:

<?php

namespace one;

trait one {

    public function setOne($data) {
        $this->data = $data;
    }

    public function getOne()
    {
        return $this->data;
    }
}

namespace two;

trait two {

    public function setTwo($data) {
        $this->data = $data;
    }

    public function getTwo()
    {
        return $this->data;
    }
}

namespace bar;

class Bar {
    use \one\one;
    use \two\two;
}

$bar = new Bar;

$bar->setOne(1);
$bar->setTwo(2);

echo "Bar getOne: " . $bar->getOne() . '<br>' . PHP_EOL; // echoes 2 instead of wanted 1
echo "Bar getTwo: " . $bar->getTwo() . '<br>' . PHP_EOL; // overwrites $this->data = 1 with 2
echo "Bar->data: " . $bar->data . '<br>' .  PHP_EOL;

每个特征都应该定义其方法所需的属性

依赖未定义的属性或在使用特性进行合成的类上定义的属性是一个坏主意。因此,拥有依赖于相同属性的多个特征也是一个坏主意

从逻辑上讲,每一个特征都应该提供它所需要的一切

此外,特征没有“范围”。当使用trait时,就好像trait中的代码被复制到消费类中一样。在您的示例中,
setOne()
getTwo()
的范围是
Bar
的一个实例,在traits中定义的方法是不相关的

更明智的做法是在特质本身中包含你的特质所需的任何属性:

例如:

通过这种方式,消费类只需从trait、complete导入它所需的行为,并可以在trait提供的属性中注入它们所需的任何内容:

class Bar
{
    use CanLog;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger; 
    }
}

我想他们是在问,如果你有另一个特点,也有
私人LoggerInterface$logger作为其定义的一部分。每个特征都可以有自己的值副本。谢谢,但在他们的示例中,它们依赖于动态生成的属性,没有任何定义。但无论如何,不管定义与否,答案都是一样的:特质没有“范围”。使用这些特征的类具有作用域。@NigelRen Yes与此完全相同。定义与否对创建一种特性自己的属性副本(范围)没有任何影响。@Jimmix是的,正如我前面所说的,它对“范围”没有任何影响。范围仍然是使用各自特性的类中的一个。@yivi对,不幸的是,它们的用例非常有限,并且在同一个类中有大量用例,其中许多不同的trait方法可以访问该类的一个或另一个属性,这使得代码几乎非常容易出错,就好像您将所有内容直接写入“主循环”,而根本不考虑范围。我看到的唯一合理的用例是trait的方法不需要超出任何属性的方法范围,但在这种情况下,可以简单地使用静态方法。这是否回答了您的问题。简言之:如果不确保属性名称的开头不同,这是不可能的(对于每个特征来说,某种前缀是唯一的)。我想补充一点,使用特质通常被认为是一种不好的做法,我建议看看@Jeto不幸的是,这是一种冲突解决技术,它消除了trait的一个方法,但我的情况是,两个trait的方法都需要,但它们使用的属性名称相同,因此一个trait的方法无意中覆盖了另一个trait的属性。因此,需要为每一个特征创建专门的范围。是的,实际上,我不太确定这个答案试图用这个样本说明什么。即使我怀疑有人会神奇地找到什么东西,我还是会取消投票结果。@Jeto我有一个小小的希望,也许如果Trait的名称空间的使用不同于类或接口名称空间的使用(Trait use语句隐式地以类名称空间开始)然后也许traits能够为它们所操作的属性提供一种子名称空间,但是因为它们仅仅是一个编译器辅助的复制和粘贴,所以我很失望。感谢您提供的链接,它们缩短了我错误的希望的时间:)您可以始终使用动态属性和
\uuuuuuuuuuuuu
。但是1)这不是很干净/方便,2)如果这样做,就无法定义实际属性,3)如果要这样做,最好手动为它们添加前缀。
class Bar
{
    use CanLog;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger; 
    }
}