PHP超类在不知道它们的情况下调用子类方法?

Gor*_*onM 6 php oop subclass superclass

在尝试调试一些PHP类时,我遇到了一些在我看来非常奇怪的行为.

我构建了以下行为的演示:

class BaseClass {
   public function baseMethod () {
      echo (implode (' ', $this -> childMethod ()) . PHP_EOL);
   }
}

class ChildClass extends BaseClass {
   protected function childMethod () {
      return array ('What', 'The', 'Actual', 'Fork!');
   }
}

$a = new ChildClass ();
$a -> baseMethod ();
Run Code Online (Sandbox Code Playgroud)

现在,在我看来,基类根本不应该对子类做任何假设,除了它通过声明(或继承)抽象方法或通过实现接口对子类强制执行的假设.但是,上面的代码实际上输出一个字符串,并没有抛出任何错误!

实际的叉子!

这对我来说似乎是破碎的行为.除非基类声明abstract protected function childMethod();,它应该不能调用它,是吗?

我一直在网上搜索,试图找到一些证明这是预期行为的东西.到目前为止,我所能找到的是PHP手册中的以下内容:

来自其他对象的可见性

即使它们不是相同的实例,相同类型的对象也可以访问彼此私有和受保护的成员.这是因为在这些对象内部时已经知道实现特定的细节

我在这里看到的行为是正确的还是PHP中的错误?这肯定不是我依赖的行为,因为它对我来说似乎不对.

仅供参考,我们在实际代码中发现的问题是子类声明了超类试图调用的私有方法.超类没有声明方法是抽象的(如果它已经完成它必须至少受到保护).

Jon*_*Jon 8

现在,在我看来,基类根本不应该对子类做任何假设,除了它通过声明(或继承)抽象方法或通过实现接口对子类强制执行的假设.

这就是静态类型语言的工作原理.在PHP(和许多其他人)中,您可以随意调用任何值的任何方法(它甚至不需要是一个对象).如果调用没有意义,则会出现运行时错误.

当然,如果您希望派生类实现它,那么声明该方法是个好主意; 这只是一种很好的做法.此外,许多着名的PHP IDE将检测到这样的遗漏并标记调用以引起您的注意,因为编译器不能.

这对我来说似乎是破碎的行为.除非基类声明 abstract protected function childMethod();,它应该不能调用它,是吗?

如上所述,它应该如此.如果您发现此行为不受欢迎,则PHP不是您应该使用的语言.

旁白:在一个密切相关的说明中,您可能还会发现,反直觉基类可以protected毫无困难地访问派生类中定义的成员.这是记录在案的.事实上,这正是你的例子中发生的事情,但我特别提到它,因为它是一种不同的反直觉(如果方法是你的例子也会令人费解public).

考虑PHP允许的无穷无尽的构造列表,从静态类型的角度来看,这也是"不可能的",包括:

// #1
$varName = 'foo';

// How do you know $object has a property named "foo"?
// How do you know that "foo" is a valid property name in the first place?
// How do you know that $object is an object to begin with?
echo $object->$varName;

// #2
$object = new SomeObject;
$methodName = 'someMethod';

// it's practically impossible to reason about this before runtime
call_user_func(array($object, $methodName));
Run Code Online (Sandbox Code Playgroud)