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