如何调用祖父素方法而不会出现E_STRICT错误?

时间:2012-10-12 00:57:24

标签: php inheritance

有时候我需要执行grandparent方法(也就是绕过父方法),我知道这是代码味道,但有时候我不能改变其他类(框架,库等)。

在PHP中,我们可以通过以下方式实现:

call_user_func(array(get_parent_class(get_parent_class($childObject)), 'grandParentMethod'));

问题是如果您启用了E_STRICT错误,您将收到如下错误:

严格标准:非静态方法GrandParent :: grandParentMethod()不应在...中静态调用

我发现只有一个解决方案(不删除E_STRICT),而只是添加@来阻止错误。

但这真的很难看,有人知道更好的解决方案吗?

谢谢! PS:我无法实例化一个新对象,如:

$grandparent = get_parent_class(get_parent_class($son));
$gp= new $grandparent;
$gp->grandParentMethod

因为我需要在$ son的上下文中调用我的祖父母方法。

4 个答案:

答案 0 :(得分:49)

您可以直接通过姓名呼叫祖父母(不需要反思,也不需要call_user_func)。

class Base {
    protected function getFoo() {
        return 'Base';
    }
}

class Child extends Base {
    protected function getFoo() {
        return parent::getFoo() . ' Child';
    }
}

class Grandchild extends Child {
    protected function getFoo() {
        return Base::getFoo() . ' Grandchild';
    }
}

Base::getFoo调用看起来像静态调用(由于冒号::语法),但事实并非如此。就像parent::也不是静态的一样。

从类中的继承链调用方法将正确绑定$this值,将其作为常规方法调用,遵守可见性规则(例如受保护),并且不违反任何类型!< / p>

起初看起来有点奇怪,但是,这是用PHP做的方法。

答案 1 :(得分:2)

您可以使用ReflectionMethod->invoke()

示例:

<?php
class Grandpa {
    protected $age = 'very old';
    public function sayMyAge() {
        return 'sayMyAge() in Grandpa should be very old. ' . 
                  'My age is: ' . $this->age;
    }
}

class Pa extends Grandpa {
    protected $age = 'less old';
    public function sayMyAge() {
        return 'sayMyAge() in Pa should be less old. ' .
                  'My age is: ' . $this->age;
    }
}

class Son extends Pa {
    protected $age = 'younger';
    public function sayMyAge() {
        return 'sayMyAge() in Son should be younger. ' .
                  'My age is: ' . $this->age;
    }
}

$son = new Son();
$reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($son)), 
                                         'sayMyAge');
echo $reflectionMethod->invoke($son);
// returns:
// sayMyAge() in Grandpa should be very old. My age is: younger

注意:调用的方法必须是公开的。

答案 2 :(得分:1)

您可以使用单独的内部方法(例如_doStuff来补充doStuff),并通过父级直接从孙中调用。

// Base class that everything inherits
class Grandpa  {
    protected function _doStuff() {
        // grandpa's logic
        echo 'grandpa ';
    }

    public function doStuff() {
        $this->_doStuff();
    }

}

class Papa extends Grandpa {
    public function doStuff() {
        parent::doStuff();
        echo 'papa ';
    }
}

class Kiddo extends Papa {
    public function doStuff() {
        // Calls _doStuff instead of doStuff
        parent::_doStuff();
        echo 'kiddo';
    }
}

$person = new Grandpa();
$person->doStuff();
echo "\n";
$person = new Papa();
$person->doStuff();
echo "\n";
$person = new Kiddo();
$person->doStuff();

显示

grandpa
grandpa papa
grandpa kiddo

答案 3 :(得分:1)

Timo的答案有效,但我认为它的偶然作用大于设计作用。如果查看$ this-> doX vs parent :: doX vs Grandparent :: doX的操作码,您会看到Grandparent :: doX作为静态方法被调用,但是PHP将使用范围内的$ this < / p>

dsd<img src="assets\test\1F619.png"/><img src="assets\test\1F619.png"/><img src="assets\test\1F629.png"/><img src="assets\test\1F630.png"/>sdfsdfsdffsdf<img src="assets\test\1F629.png"/>sdfsdsdfsdf<img src="assets\test\1F627.png"/><img src="assets\test\1F631.png"/>sdfsdfsdf<img src="assets\test\1F631.png"/>sdfsdfsdf<img src="assets\test\1F632.png"/>sdfsdfs<img src="assets\test\1F629.png"/><img src="assets\test\1F629.png"/>sdfs<img src="assets\test\1F631.png"/>df<img src="assets\test\1F632.png"/>sdfsdfsdf

由于此原因,$ this参数在祖父母的静态调用中可用(来自https://www.php.net/manual/en/language.oop5.basic.php):

  

当从对象上下文中调用方法时,伪变量$ this可用。 $ this是对调用对象的引用(通常是该方法所属的对象,但如果从辅助对象的上下文中静态调用该方法,则可能是另一个对象)。从PHP 7.0.0开始,从不兼容的上下文中静态调用非静态方法会导致$ this在方法内部未定义。从PHP 5.6.0开始,不赞成从不兼容的上下文中静态调用非静态方法。自PHP 7.0.0起,通常不建议静态调用非静态方法(即使从兼容上下文调用)。在PHP 5.6.0之前,此类调用已经触发了严格的通知。