3

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

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
            ....
    }

}
4

4 回答 4

5

他们做两种不同的事情。关键字的语义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()vs. $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() 时应该始终没问题。

于 2012-12-07T14:05:56.267 回答
1

据我了解,这是两个不同的东西。

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

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

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

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

希望我能有所帮助。

于 2012-12-07T14:09:24.480 回答
0

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

于 2012-12-07T13:30:14.083 回答
0

有关从子类调用受保护的父方法的示例,请参见下文。

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

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
于 2020-04-02T08:37:45.547 回答