我可以使用至少两种基本方法从子类访问protected类方法:
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()
)是,您没有考虑到该类是其父级的[[grand child ,例如...
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相似。请参见下面的两个实现示例。这样做的一个很好的理由是重用父级的功能,然后将其添加到子类中。
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