Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/239.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 如何调用祖父母方法而不产生E_严格错误?_Php_Inheritance - Fatal编程技术网

Php 如何调用祖父母方法而不产生E_严格错误?

Php 如何调用祖父母方法而不产生E_严格错误?,php,inheritance,Php,Inheritance,有时我需要执行祖父母方法(即绕过父方法),我知道这是代码味道,但有时我无法更改其他类(框架、库等) 在PHP中,我们可以通过以下方式实现: call_user_func(array(get_parent_class(get_parent_class($childObject)), 'grandParentMethod')); 问题是,如果启用了E_STRICT errors,则会出现如下错误: 严格标准:不应在中静态调用非静态方法祖父母::祖父母方法() 我只找到了一个解决方案(没有删除E_S

有时我需要执行祖父母方法(即绕过父方法),我知道这是代码味道,但有时我无法更改其他类(框架、库等)

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

call_user_func(array(get_parent_class(get_parent_class($childObject)), 'grandParentMethod'));
问题是,如果启用了E_STRICT errors,则会出现如下错误:

严格标准:不应在中静态调用非静态方法祖父母::祖父母方法()

我只找到了一个解决方案(没有删除E_STRICT),它只是添加
@
来抑制错误

但这真的很难看,有人知道更好的解决办法吗

谢谢! PS:我无法实例化如下新对象:

$grandparent = get_parent_class(get_parent_class($son));
$gp= new $grandparent;
$gp->grandParentMethod
因为我需要在$son的上下文中调用我的祖父母方法。

您可以使用

例如:

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

您可以使用单独的内部方法(例如,
\u 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();
显示


您可以直接按名称调用祖父母(不需要反射,也不需要调用用户函数)

Base::getFoo
调用可能看起来像一个静态调用(由于冒号
语法),但是它不是。就像
parent::
也不是静态的

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


这一点乍看起来可能有点奇怪,但这是用PHP实现的方法。

Timo的答案是可行的,但我认为它是偶然的,而不是设计的。如果查看$this->doX与父::doX与祖父母::doX的操作码,您可以看到祖父母::doX是作为静态方法调用的,但PHP将使用范围内的$this

$this->doX
  17     1        EXT_STMT                                                 
         2        INIT_METHOD_CALL                               'doX'
         3        EXT_FCALL_BEGIN                                          
         4        DO_FCALL                                      0          
         5        EXT_FCALL_END                                            

parent::doX
  18     6        EXT_STMT                                                 
         7        FETCH_CLASS                                 514  :1      
         8        INIT_STATIC_METHOD_CALL                     $1, 'doX'
         9        EXT_FCALL_BEGIN                                          
        10        DO_FCALL                                      0          
        11        EXT_FCALL_END                                            

Grandparent::doX
  19    12        EXT_STMT                                                 
        13        INIT_STATIC_METHOD_CALL                  'C1', 'doX'
        14        EXT_FCALL_BEGIN                                          
        15        DO_FCALL                                      0          
        16        EXT_FCALL_END                                            
$this参数在祖父母的静态调用中可用,因为(从):

当从对象上下文中调用方法时,伪变量$this可用$这是对调用对象的引用(通常是该方法所属的对象,但如果该方法是从辅助对象的上下文静态调用的,则可能是另一个对象)。从PHP7.0.0开始,从不兼容的上下文静态调用非静态方法会导致$this在方法中未定义。从PHP5.6.0开始,不推荐从不兼容的上下文静态调用非静态方法。从PHP7.0.0开始,静态调用非静态方法通常被弃用(即使是从兼容的上下文调用)。在PHP5.6.0之前,此类调用已经触发了严格的通知


我想我们可以对非公共方法使用setAccessible。不管怎样,这美元在哪里?在大多数情况下,我需要在我的子类中使用grandparent,grandparent必须更改$this(son)对象上的内容,而不是新对象。奇怪的是,在本例中,当我执行以下操作时,PHP(5.3.13)没有显示E_SRICT警告:祖父母::方法();在我的子类中(并且假设$this是正确的)。我无法告诉您为什么从类中调用
祖父母::方法()
不会强制执行严格警告$在本例中,这将是调用方法$son的对象,因此对$this的更改将应用于这里的$son。我有同样的问题,但根据,如果上下文是正确的(我假设这意味着“来自子类”),调用
祖父母::方法()
将正确设置
$this
,并允许以静态方式进行此非静态调用。这是一种比公认答案更简洁的方法。直到今天我才知道你可以用PHP做这个。。。谢谢@KrinkleHey-Enrique,看起来Krinkle的答案更合适、更清晰。它也不要求您在祖父类上设置公共访问权限,以便从孙子类访问它。。。如果你同意,你能把被接受的答案改成克林克的答案吗?
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';
    }
}
$this->doX
  17     1        EXT_STMT                                                 
         2        INIT_METHOD_CALL                               'doX'
         3        EXT_FCALL_BEGIN                                          
         4        DO_FCALL                                      0          
         5        EXT_FCALL_END                                            

parent::doX
  18     6        EXT_STMT                                                 
         7        FETCH_CLASS                                 514  :1      
         8        INIT_STATIC_METHOD_CALL                     $1, 'doX'
         9        EXT_FCALL_BEGIN                                          
        10        DO_FCALL                                      0          
        11        EXT_FCALL_END                                            

Grandparent::doX
  19    12        EXT_STMT                                                 
        13        INIT_STATIC_METHOD_CALL                  'C1', 'doX'
        14        EXT_FCALL_BEGIN                                          
        15        DO_FCALL                                      0          
        16        EXT_FCALL_END