【问题标题】:how static variables in traits don't lose its value when used inside class in PHP?在 PHP 的类中使用时,特征中的静态变量如何不失去其价值?
【发布时间】:2018-01-26 17:00:14
【问题描述】:

trait 中的静态属性在被类使用时如何不会失去其价值 尽管 Traits 是语言辅助的复制/粘贴? 让我们考虑以下示例,

     trait Test{
    public static $var = 1;

   public static  function increment(){
        self::$var ++;
        var_dump(self::$var);
    }
}


Test::increment();//2



class Test2{

    use Test;

}

var_dump(Test2::$var);//2
Test2::increment();//3

这种行为在子继承父的继承中是正确的,因此子使用父静态变量,但是根据应用复制和粘贴的特征,这是如何工作和正确的?


这是为我的困惑添加另一个原因的更新, 如果静态值保留给特定上下文(如特定类或函数),那么我如何能够使用来自不同上下文(新类)的静态属性的更新值。 我的意思是,如果 trait Test 的上下文被称为 Context1,而 Test2 类的上下文被称为 Context2,我如何在另一个上下文中访问第一个上下文的保留值?这与我们理解的上下文方法背道而驰。


更新 3: 所有这些混淆都取决于 use 关键字是在类中导入特征成员还是复制/粘贴?

【问题讨论】:

    标签: php oop static traits


    【解决方案1】:

    虽然 Traits 是语言辅助的复制/粘贴,但 Traits 中的静态属性在被类使用时如何不会失去其价值?

    特征有自己的上下文,独立于使用该特征的类,至少对于静态属性而言。如果一个类使用带有静态属性的 trait,则该类会获得自己的上下文,即“它自己的”静态属性,其初始值是从 trait 复制而来的:

    trait T {
        // '$staticProp' exists in the context of T
        public static $staticProp = "in T\n";
    }
    
    // Without the need of a class that implements the trait, you can already access its value explicitly:
    echo T::$staticProp; // in T
    
    class A {
        // Now 'A' gets its own '$staticProp', the initial value is copied from the context of the trait 'T'
        use T;
    }
    
    // Now you can access 'A's '$staticProp' explicitly:
    echo A::$staticProp; // in T
    
    // Now we can explicitly change the value of 'A's '$staticProp'. Because 'A' has its own context, 'T::$staticProp' stays untouched:
    A::$staticProp = "in A\n";
    
    echo A::$staticProp; // in A
    echo T::$staticProp; // in T
    

    这是一个更新,为我的困惑添加了另一个原因......我的意思是,如果调用 trait Test 的上下文,例如 Context1,并且类 Test2 上下文称为 Context2,我如何访问保留值在另一个上下文中的第一个上下文?

    正如我所展示的,您始终可以使用类/特征名称和范围解析运算符 (::) 访问特定上下文的静态属性:

    T::$staticProp; // Access context of trait T
    A::$staticProp; // Access context of class A
    

    所有这些混淆取决于 use 关键字是在类中导入特征成员还是复制/粘贴?

    我认为理解行为的最佳方式如下:

    1. 单独的 trait 总是有自己的上下文和自己的当前值状态。
    2. 当一个类使用该特征时,所有成员都将复制其当前值。现在类和特征有两个独立的上下文,每个上下文都有自己的状态。
    3. 更改一个上下文的值不会影响另一个上下文。

    让我们考虑以下示例,

    这是您的示例中发生的情况:

    对于类,子类包括其父类的上下文:

    class A {
        public static $staticProp = "I am in debt\n";
    }
    
    class B extends A {}
    
    echo A::$staticProp; // I am in debt
    echo B::$staticProp; // I am in debt
    
    A::$staticProp = "Even more debts\n";
    
    echo A::$staticProp; // Even more debts
    echo B::$staticProp; // Even more debts
    
    B::$staticProp = "Paid debts, now debt-free\n";
    
    echo A::$staticProp; // Paid debts, now debt-free
    echo B::$staticProp; // Paid debts, now debt-free   
    

    self 如果我们尝试访问继承的成员,通常会引用它所在的类或其父类:

    class A {
        public static $aProp = 0;
    }
    
    class B extends A {
        public static $bProp = 0;
    
        public static function setProps() {
            // Because B has a non inherited property '$bProp' 'self' will reference the context of class 'B':
            self::$bProp = 12;
    
            // Because B inherits a property '$aProp' 'self' will reference the inherited context of class 'A':
            self::$aProp = 23;
        }
    
        public static function printProps() {
            echo 'self::$bProp: ' . self::$bProp . "\n";
            echo 'self::$aProp: ' . self::$aProp . "\n";
        }
    }
    
    B::setProps();
    B::printProps();
        // self::$bProp: 12
        // self::$aProp: 23
    
    A::$aProp; // 23
    B::$aProp; // 23
    
    // Again 'A' and 'B' share the same context:
    A::$aProp = 0;
    echo B::$aProp; // 0
    

    当使用特征self 时,要么引用特征上下文,要么引用一个类的独立副本。这就是您的示例中发生的情况:

    trait Test {
        public static $var = 1;
    
        public static function increment() {
            self::$var++;
            var_dump(self::$var);
        }
    }
    
    // This will increment '$var' in the context of trait 'Test'
    Test::increment(); // 2
    
    // Access '$var' of trait context 'Test':
    var_dump(Test::$var); // 2
    
    class Test2 {
        // Members of 'Test' are copied with current values (2) in the context of class 'Test2'
        use Test;
    }
    
    // Access '$var' of class context 'Test2':
    var_dump(Test2::$var); // 2
    
    // This will increment '$var' in the context of class 'Test2'
    Test2::increment(); // 3
    
    // '$var' of trait context 'Test' has not changed:
    var_dump(Test::$var); // 2
    

    【讨论】:

      【解决方案2】:

      来自Trait Documentation

      Trait 类似于类,但仅用于分组 以细粒度和一致的方式实现功能。这不可能 自己实例化一个 Trait。它是对传统的补充 继承并使行为的水平组合成为可能;那是, 无需继承即可应用类成员

      您不能单独实例化一个 Trait,也不能定义 Trait 使用的属性,因为它们会发生冲突,这是因为 Trait 将此功能“添加”到您附加的类中到。

      【讨论】:

      • 我没看懂你回答的方方面面,但是根据我的理解,问题不在于traits是一个有更多或更少特性的类,问题是我们没有使用继承不会丢失静态属性的上下文值,我们只是将属性和方法从 trait 复制/粘贴到类,那么这种行为是如何复制旧的静态值的呢?
      • 我将编辑我的问题,为我的困惑添加另一个证据。
      • 这个答案在任何情况下都不能回答关于特征具有静态属性时不同上下文的问题......
      猜你喜欢
      • 1970-01-01
      • 2014-03-09
      • 1970-01-01
      • 2021-09-20
      • 2017-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多