简体   繁体   English

访问父变量和子变量在父定义的方法中 - PHP

[英]Access parent and child variables in method defined in parent - PHP

I have a child object that inherits from a parent.我有一个从父对象继承的子对象。 Both have a static variable which has a different value in each object;两者都有一个静态变量,它在每个对象中都有不同的值; I want to add that variable from both parent and child to an array when I instantiate the child.当我实例化子项时,我想将该变量从父项和子项添加到数组中。 To save duplicating code, I've written a method ( addFoo ) in the parent which is called from both the parent and the child constructors.为了节省重复的代码,我在父类中编写了一个方法( addFoo ),该方法从父类和子类构造函数中调用。 However, I can't seem to find a way to distinguish between the calls when the parent constructor is called from the child constructor (as you can see below, the output from the method is the same in both cases whether using $this , self or static ).但是,我似乎无法找到一种方法来区分从子构造函数调用父构造函数时的调用(如下所示,无论使用$this self ,方法的输出在两种情况下都是相同的)或static )。

class A {
    public static $foo = 'foo';
    
    public $thisvars = array();
    public $selfvars = array();
    public $staticvars = array();
    
    public function __construct() {
        $this->addFoo();
    }
    
    public function addFoo() {
        $this->selfvars[] = self::$foo;
        $this->staticvars[] = static::$foo;
        $this->thisvars[] = $this::$foo;
    }
    
}

class B extends A {
    public static $foo = 'bar';
    
    public function __construct() {
        parent::__construct();
        $this->addFoo();
    }
}

$b = new B;
print_r($b->selfvars);
print_r($b->staticvars);
print_r($b->thisvars);

Output:输出:

Array
(
    [0] => foo
    [1] => foo
)
Array
(
    [0] => bar
    [1] => bar
)
Array
(
    [0] => bar
    [1] => bar
)

I can workaround this by passing the calling class through to the addFoo function (see below), but is there a better (correct?) way?我可以通过将调用类传递给addFoo函数(见下文)来解决这个问题,但是有没有更好的(正确的?)方法吗?

class C {
    public static $foo = 'foo';
    
    public $vars = array();
    
    public function __construct() {
        $this->addFoo(__CLASS__);
    }
    
    public function addFoo($class) {
        $this->vars[] = $class::$foo;
    }
    
}

class D extends C {
    public static $foo = 'bar';
    
    public function __construct() {
        parent::__construct();
        $this->addFoo(__CLASS__);
    }
}

$d = new D;
print_r($d->vars);

Output:输出:

Array
(
    [0] => foo
    [1] => bar
)

Demo on 3v4l.org 3v4l.org 上的演示

Instead of having addFoo be called by every sub-constructor, one way would be to have a single addFoos method in the base class that is called by the base constructor, that would append all the $foo values starting from the late static binding class:不是让每个子构造函数都调用addFoo ,一种方法是在基构造函数调用的基类中使用单个addFoos方法,该方法将从后期静态绑定类开始附加所有$foo值:

class A
{
    public static $foo = 'foo';

    public $vars = [];

    public function __construct()
    {
        $this->addFoos();
    }

    private function addFoos()
    {
        $class = static::class;
        do {
            $this->vars[] = $class::$foo;
        } while ($class = get_parent_class($class));
    }

}

class B extends A
{
    public static $foo = 'bar';
}

class C extends B
{
    public static $foo = 'baz';
}

$a = new A;
print_r($a->vars);  // ['foo']

$b = new B;
print_r($b->vars);  // ['bar', 'foo']

$c = new C;
print_r($c->vars);  // ['baz', 'bar', 'foo']

That method is marked private as it's not supposed to be extended in this scenario (nor called from the outside).该方法被标记为private因为在这种情况下它不应该被扩展(也不应该从外部调用)。

Demo演示

I would alternatively consider another, more straightforward approach:我或者会考虑另一种更直接的方法:

class A
{
    public static $foo = 'foo';

    public function getVars()
    {
        return [self::$foo];
    }
}

class B extends A
{
    public static $foo = 'bar';

    public function getVars()
    {
        return array_merge(parent::getVars(), [self::$foo]);
    }
}

class C extends B
{
    public static $foo = 'baz';

    public function getVars()
    {
        return array_merge(parent::getVars(), [self::$foo]);
    }
}

$a = new A;
print_r($a->getVars());  // ['foo']

$b = new B;
print_r($b->getVars());  // ['foo', 'bar']

$c = new C;
print_r($c->getVars());  // ['foo', 'bar', 'baz']

You do have to redefine getVars on each subclass in this case, but after all, it makes sense for each class to decide which variables should be exposed.在这种情况下,您确实必须在每个子类上重新定义getVars ,但毕竟,每个类决定应该公开哪些变量是有意义的。 Your code becomes a bit less obscure / easier to maintain in the process.在此过程中,您的代码变得不那么晦涩/更易于维护。

And if a class doesn't need/want to "contribute", you can simply omit both the static property and the getVars extension for that class.如果一个类不需要/想要“贡献”,您可以简单地省略getVars的静态属性和getVars扩展。

Demo演示

Notes:笔记:

  • you can easily cache the variables into a $vars property inside A if needed,如果需要,您可以轻松地将变量缓存到A$vars属性中,
  • order is swapped from the other answer but you can obviously swap the array_merge if needed,顺序是从另一个答案交换的,但如果需要,您显然可以交换array_merge
  • in both this sample and the one from the other answer, I'm not sure if the $foo static properties need to be public , but I've left them like they were in your question.在此示例和另一个答案中的示例中,我不确定$foo静态属性是否需要是public ,但我已经将它们保留为您的问题中的样子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM