PHP检查继承的父项是否存在(当前范围而不是$this)

PHP检查继承的父项是否存在(当前范围而不是$this),php,inheritance,parent,Php,Inheritance,Parent,我希望我能把这写清楚 案例: 我有一个基类Foo Foo可以有一个方法(在示例中)::run 另一个类Bar扩展了Foo,并有自己的方法::runBar(以及编写Bar)的开发人员不知道父Foo是否拥有或将拥有方法::run 这就是为什么Bar无论如何都要在parent上调用当前方法的原因 助手方法::callParentMethodIfExists应执行其工作,并检查$method是否存在于parent上 到目前为止还不错: 调用Bar::run Bar::run调用::callParent

我希望我能把这写清楚

案例:

我有一个基类
Foo

Foo可以有一个方法(在示例中)
::run

另一个类
Bar
扩展了
Foo
,并有自己的方法
::run
Bar
(以及编写
Bar
)的开发人员不知道父
Foo
是否拥有或将拥有方法
::run

这就是为什么
Bar
无论如何都要在
parent
上调用当前方法的原因

助手方法
::callParentMethodIfExists
应执行其工作,并检查
$method
是否存在于
parent

到目前为止还不错:

  • 调用
    Bar::run
  • Bar::run
    调用
    ::callParentMethodIfExists
  • ::callParentMethodIfExists
    调用
    parent::run
    如果存在
问题:

如果现在一个类
Baz
扩展了
Bar
并且
Baz
没有具有
::run
方法,那么:

  • 调用从
    Bar
  • 正在执行
    Bar::run
  • Bar::run
    调用
    ::callParentMethodIfExists
  • ::callParentMethodIfExists
    调用
    ::parentMethodExists
    并检查
    $this
    Baz
    )是否有父方法
    ::run
所以这是真的,因为
Baz
有一个
parent::run
(即
Bar::run
ofc)但这不是我应该检查它的范围

简言之

助手方法
::callParentMethodIfExists
::parentMethodExists
应该检查
$this
。他们应该在有问题的方法首次出现时检查范围


代码

class Foo
{
    public function run()
    {
        echo __METHOD__ . PHP_EOL;
    }
}

class Bar extends \Foo
{
    public function run()
    {
        $this->callParentMethodIfExists(__FUNCTION__);

        echo __METHOD__ . PHP_EOL;
    }

    /**
     * Calls the given parent method if exists.
     *
     * @param string $method
     *
     * @return null|mixed
     */
    protected function callParentMethodIfExists($method)
    {
        if ($this->parentMethodExists($this, $method)) {
            return parent::$method();
        }
        return null;
    }

    /**
     * @param mixed  $class  An object (class instance) or a string (class name).
     * @param string $method The method name.
     *
     * @return bool
     */
    public function parentMethodExists($class, $method)
    {
        foreach (class_parents($class) as $parent) {
            if (method_exists($parent, $method)) {
                return true;
            }
        }
        return false;
    }
}

class Baz extends \Bar{}

(new \Baz())->run();
// out:
// Foo::run
// Bar::run
class Foo{}

class Bar extends \Foo
{
    public function run()
    {
        $this->callParentMethodIfExists(__FUNCTION__);

        echo __METHOD__ . PHP_EOL;
    }

    /**
     * Calls the given parent method if exists.
     *
     * @param string $method
     *
     * @return null|mixed
     */
    protected function callParentMethodIfExists($method)
    {
        if ($this->parentMethodExists($this, $method)) {
            return parent::$method();
        }
        return null;
    }

    /**
     * @param mixed  $class  An object (class instance) or a string (class name).
     * @param string $method The method name.
     *
     * @return bool
     */
    public function parentMethodExists($class, $method)
    {
        foreach (class_parents($class) as $parent) {
            if (method_exists($parent, $method)) {
                return true;
            }
        }
        return false;
    }
}

class Baz extends \Bar{}

(new \Baz())->run();
// out:
// Fatal error: Uncaught Error: Call to undefined method Foo::run() in 
工作案例

class Foo
{
    public function run()
    {
        echo __METHOD__ . PHP_EOL;
    }
}

class Bar extends \Foo
{
    public function run()
    {
        $this->callParentMethodIfExists(__FUNCTION__);

        echo __METHOD__ . PHP_EOL;
    }

    /**
     * Calls the given parent method if exists.
     *
     * @param string $method
     *
     * @return null|mixed
     */
    protected function callParentMethodIfExists($method)
    {
        if ($this->parentMethodExists($this, $method)) {
            return parent::$method();
        }
        return null;
    }

    /**
     * @param mixed  $class  An object (class instance) or a string (class name).
     * @param string $method The method name.
     *
     * @return bool
     */
    public function parentMethodExists($class, $method)
    {
        foreach (class_parents($class) as $parent) {
            if (method_exists($parent, $method)) {
                return true;
            }
        }
        return false;
    }
}

class Baz extends \Bar{}

(new \Baz())->run();
// out:
// Foo::run
// Bar::run
class Foo{}

class Bar extends \Foo
{
    public function run()
    {
        $this->callParentMethodIfExists(__FUNCTION__);

        echo __METHOD__ . PHP_EOL;
    }

    /**
     * Calls the given parent method if exists.
     *
     * @param string $method
     *
     * @return null|mixed
     */
    protected function callParentMethodIfExists($method)
    {
        if ($this->parentMethodExists($this, $method)) {
            return parent::$method();
        }
        return null;
    }

    /**
     * @param mixed  $class  An object (class instance) or a string (class name).
     * @param string $method The method name.
     *
     * @return bool
     */
    public function parentMethodExists($class, $method)
    {
        foreach (class_parents($class) as $parent) {
            if (method_exists($parent, $method)) {
                return true;
            }
        }
        return false;
    }
}

class Baz extends \Bar{}

(new \Baz())->run();
// out:
// Fatal error: Uncaught Error: Call to undefined method Foo::run() in 
非工作案例

class Foo
{
    public function run()
    {
        echo __METHOD__ . PHP_EOL;
    }
}

class Bar extends \Foo
{
    public function run()
    {
        $this->callParentMethodIfExists(__FUNCTION__);

        echo __METHOD__ . PHP_EOL;
    }

    /**
     * Calls the given parent method if exists.
     *
     * @param string $method
     *
     * @return null|mixed
     */
    protected function callParentMethodIfExists($method)
    {
        if ($this->parentMethodExists($this, $method)) {
            return parent::$method();
        }
        return null;
    }

    /**
     * @param mixed  $class  An object (class instance) or a string (class name).
     * @param string $method The method name.
     *
     * @return bool
     */
    public function parentMethodExists($class, $method)
    {
        foreach (class_parents($class) as $parent) {
            if (method_exists($parent, $method)) {
                return true;
            }
        }
        return false;
    }
}

class Baz extends \Bar{}

(new \Baz())->run();
// out:
// Foo::run
// Bar::run
class Foo{}

class Bar extends \Foo
{
    public function run()
    {
        $this->callParentMethodIfExists(__FUNCTION__);

        echo __METHOD__ . PHP_EOL;
    }

    /**
     * Calls the given parent method if exists.
     *
     * @param string $method
     *
     * @return null|mixed
     */
    protected function callParentMethodIfExists($method)
    {
        if ($this->parentMethodExists($this, $method)) {
            return parent::$method();
        }
        return null;
    }

    /**
     * @param mixed  $class  An object (class instance) or a string (class name).
     * @param string $method The method name.
     *
     * @return bool
     */
    public function parentMethodExists($class, $method)
    {
        foreach (class_parents($class) as $parent) {
            if (method_exists($parent, $method)) {
                return true;
            }
        }
        return false;
    }
}

class Baz extends \Bar{}

(new \Baz())->run();
// out:
// Fatal error: Uncaught Error: Call to undefined method Foo::run() in 
正如您在not working case上看到的那样,
Foo
类没有
::run
方法

调用的类(
$this
)是
Baz

Baz
继承的方法
::从
栏运行

Bar::run
调用
::callParentMethodIfExists

错误地,两个helper方法都检查
$this
Baz
)并发现
Baz
有一个
parent::run

实际上,这两种辅助方法都应该检查当前范围
Bar
),并发现
Bar
具有
parent::run


我希望这是可以理解的,有人知道一个解决办法

提前谢谢

/科顿


编辑
::callParentMethodIfExists
::parentMethodExists
也可以在
Foo
上定义,或者作为
trait
包含
trait

可能我不理解这种情况,但我会写
Bar::run()
,就这么简单:

public function run()
{
    if (method_exists('Foo', 'run')) {
        Foo::run();
    }

    echo __METHOD__ . PHP_EOL;
}
您知道,
Bar扩展了Foo
,不需要对父类和所有内容进行太多的调查


Bar
的子项可以重新定义方法
run()
,也可以不重新定义。只要它们调用
parent::run()
在他们的新定义中,调用链最终将到达调用
Foo::run()
Bar::run()
,如果它存在的话。

哎哟,我的滚动手指抽筋了:-(这似乎很迂回。为什么不直接声明
Foo::run
final?@AlexHowansky我不能。在实际代码中,“主机”类调用“回调”(?)。它的Phalcon\Mvc\模型可以有
::beforeSave
ect。这个解决方案可能会对您有效:我需要动态地使用它。在实际代码中,这两种方法都是traits。因此它无法修复cal来自ect的位置。