从PHP中的子类访问受保护的方法



我可以使用至少两种基本方法从子类访问受保护的类方法:

parent::myMethod();
$this->myMethod();

如果我不需要在子类中覆盖它,在这种情况下,我必须这样做:

function myMethod() {
...
parent::myMethod();
...
}

最推荐的称呼方式是什么?我个人觉得使用parent::myMethod()而不是$this->myMethod更舒服,因为第一个方法会立即告诉我这个方法正在被继承。但我不确定在性能和最佳实践方面是哪种方式。

编辑:

看看这个,这是我问题的真实情况。它使用CodeIgniter,但即使你不熟悉它,你也可能会得到它:

class Admin_Controller extends CI_Controller {
protected function validate_form($validation) {
$this->load->library('form_validation');
// This will validate the form sent against the validation rules group specified in $validation
if ($this->form_validation->run($validation) == false) {   
throw new Exception('There are errors in the form');
}
}
}
class Articles extends Admin_Controller {
function save($id) {
$this->validate_form(strtolower(get_class($this));
// OR
parent::validate_form(strtolower(get_class($this));
// Other actions
....
}
}
class Login extends Admin_Controller {
function signIn() {
$this->validate_form(strtolower(get_class($this));
// OR
parent::validate_form(strtolower(get_class($this));
// Other actions
....
}
}

他们做两件不同的事情。parent关键字的语义使得它对其父类进行转发调用。然而,$this->method()的语义是这样的,即只有在调用该方法的实例没有声明该方法的情况下,它才会将调用转发到父类。同样重要的是要注意,孩子可能有父母,也可能有祖父母,因此在设计原型时也必须仔细考虑这一点。

如果不希望覆盖该方法,则应在方法原型声明中使用final关键字。

class MyClass {
final protected function myMethod() {
}
}

这确保任何扩展类都不能覆盖方法。如果扩展类试图像下面的代码一样重写此方法,则会得到Fatal error: Cannot override final method MyClass::myMethod()的致命错误。

class MyOtherClass extends MyClass {
public function myMethod() {
}
}

此外,这使您的代码更具可读性,并且不易出错因为您明确地向读取代码的人声明该方法是最终方法,不能重写。

此外,您的方法的根本问题(如果您想使用parent::myMethod()$this->myMethod())是,您没有考虑当类是其父级的孙子时会发生什么,例如。。。

class Father {
protected function myMethod() {
return __METHOD__;
}
}
class Child extends Father {
public function myMethod() {
return __METHOD__;
}
}
class GrandChild extends Child {
public function myOtherMethod() {
echo parent::myMethod(), "n"; // Child::myMethod
echo $this->myMethod(), "n";  // Child::myMethod
}
}
$obj = new GrandChild;
$obj->myOtherMethod();

正如你所看到的,即使你打算采用父亲的方法,他们都会给你孩子的方法。如果您从未打算在扩展类中重写该方法,只需将其声明为final即可,并且在从对象上下文调用$this->myMethod()时应该总是很好的。

据我所知,这是两件不同的事情。

$this用于引用类的实例,并且在创建对象后可用。因此,它将引用子类的对象,而不是父类。

parent是在子类中扩展父方法的正确方法。它引用了父类,并具有额外的优势,即不需要在多个级别上更改类名self类似。

有关示例,请参阅下面的两个实现。

  1. 使用父关键字访问
  2. 使用此访问会导致意外行为

希望我能帮上忙。

当您调用parent::method()时,它与$this->method(。如果您在子类中覆盖它,它可能会返回不同的值

请参阅下面的子类对受保护父方法的调用示例。

这样做的一个很好的理由是重用父类中的功能,然后将其添加到子类中。

class A{
protected $a;
public function __construct(){
$this->setValueOfStringInA();
}
protected function setValueOfStringInA(){
$this->a = "a set from A::setValueOfStringInA";
}
public function getValueOfA(){
echo 'a of ' . __CLASS__ . ' = ' . $this->a . '<br>';
}
}
class B extends A{
protected $b;
public function __construct(){
parent::__construct();
}
protected function setValueOfStringInA(){
parent::setValueOfStringInA();
$this->b = "b set from B::setValueOfStringInA";
}
public function getValueOfA(){
echo 'a of ' . __CLASS__ . ' = ' . $this->a . '<br>';
}    
public function getValueOfB(){
echo 'b of ' . __CLASS__ . ' = ' . $this->b . '<br>';
}
}
$objA = new A();
//the following call will not work since it is a protected method, it can not be called from outside, hence commented out.
//$objA->setValueOfStringInA();
$objA->getValueOfA();
$objB = new B();
//$objB->setValueOfStringInA();
$objB->getValueOfB();
$objB->getValueOfA();

检查输出:

a of A = a set from A::setValueOfStringInA
b of B = b set from B::setValueOfStringInA
a of B = a set from A::setValueOfStringInA

最新更新