Access protected method from child class in PHP
Solution 1
They do two different things. The semantic of the parent
keyword is such that it does a forwarding call to its parent class. The semantics of $this->method()
, however, are such that it will only forward its call to the parent class in the event that the instance on which the method is called does not declare that method. It's also important to note that a child may have a parent as well as a grand parent so that must be taken into careful consideration as well in the design of the prototype.
If you don't want the method to be overridden you should use the final keyword in the method prototype declaration.
class MyClass {
final protected function myMethod() {
}
}
This ensures that any extending class will not be able to override the method. If an extending class attempts to override this method like the following code, you would get a fatal error of Fatal error: Cannot override final method MyClass::myMethod()
.
class MyOtherClass extends MyClass {
public function myMethod() {
}
}
Also, this makes your code more readable and less prone to error since you are clearly stating to whoever reads the code that the method is final and cannot be overridden.
Also, the underlying problem with your approach (if you want to use parent::myMethod()
vs. $this->myMethod()
) is that you aren't taking into account what happens when the class is a grand child of its parent, for example...
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();
As you can see they will both give you the child method even if you meant to get at the father's method. Just declare the method as final if you never intend to override it in the extending classes and you should always be fine when calling $this->myMethod() from object context.
Solution 2
As far as I understand it, those are two different things.
$this is used to refer to an instance of the class, and will be available once an an object is created. It will therefore refer to the child classs objects, and not the parent.
parent is the correct way to extend a parent's method in the sub class. It refers to the parent class, and has the added advantage that changes in class names do not need to be done on many levels. self is similar.
See the two implementations below for an example.
Hope I could be of help.
Related videos on Youtube
Luis Martin
Updated on August 20, 2022Comments
-
Luis Martin over 1 year
I can use at least two basic ways to access a protected class method from a child class:
parent::myMethod(); $this->myMethod();
If I don't need to override it in the child class, in which case I would have to do this:
function myMethod() { ... parent::myMethod(); ... }
which is the most recommended way to call it? I personally feel more comfortable using parent::myMethod() rather than $this->myMethod, because the first one immediately tells me this method is being inherited. But I'm not sure which way in terms of performance and best practices.
EDIT:
Check this, which is the real case of my question. It's using CodeIgniter, but even though you're not familiar with it, you will likely get it:
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 .... } }
-
Luis Martin over 11 yearsYou mean none of them are considered a bad practice?
-
Wesley Murch over 11 yearsTechnically speaking
parent::myMethod()
and$this->myMethod()
are two different things and may return different results... the second one refers to the child class. -
Wesley Murch over 11 yearsWhat is the
...
part? Why would you need either one if you aren't overriding the parent method? Can you give a more realistic example? -
Luis Martin over 11 years@Wesley Murch: Yes, they are technically different because parent::myMethod() is the method in the parent class and this->myMethod() is the inherited method in the child class. But, if this method is not overriden, could I expect different results?? Ignore the '...' parts, it's an example I made in case I needed to override the method, which is not the case.
-
Wesley Murch over 11 yearsBut, you are overriding
myMethod
in your example, and calling the parentmyMethod
in your childmyMethod
. Try a better example, or try to clarify your question in some way that makes it more tangible or realistic. Just calling the parent method without any modification makes no sense. -
Peter Adrian over 11 yearsActually, the first one is a good practice ... to unnecessary override methods you are just making your code more "complex". You added just one more method that does nothing at all. And this means one more operation to do for the program. If you are looking to have optimized code, this is not a good practice.
-
-
Ed Heal over 11 yearsHe did mention "If I don't need to override it in the child class"
-
Wesley Murch over 11 yearsBut of course he's calling
myMethod
from the child methodmyMethod
which makes the question very confusing. -
v0d1ch over 11 yearsWell if you don't override it you cant call it with $this right ?
-
v0d1ch over 11 years@ Wesley Murch : use $this-> to call method that doesen't exist except in parent class ? Yeah I'm a bit sleepy :)
-
v0d1ch over 11 yearsYea, Yea I know don't rub it in :)
-
Luis Martin over 11 yearsRight now the only thing I have clear is what Ed Heal said: both ways are valid. Is it so? Note again I don't want to override the method. I just need to "use" it in several children classes. To do this, I need to declare the method protected. But in this case, PHP is automatically allowing me to use an inherited method ($this->myMethod), or the parent's (parent::myMethod), which would do exactly the same actions. So, what would you do then?
-
v0d1ch over 11 yearsEd Heal also said just a matter of taste. I prefer $this
-
Sherif over 11 yearsThat is technically incorrect.
parent::method()
is a direct forwarding call to the parent class (meaning even if the method is overridden by that class it will be forwarded to its parent).$this->method()
may very well get forwarded to its parent in the event the child does not override its parent's method. However, I agree with you that using parent is an explicit way to ensure you use the parent method and not the child method. But I also would like to add thatself
does not allow for LSB (Late Static Binding) which could get you in some trouble as well ;) -
Awemo over 11 yearsI am trying to find out how far up parent goes, cannot find any information. The most important point I wanted to make was that $this refers to the objects and starts looking from the current context upwards, while parent goes directly to the parent. Your answer is however correct because he specifically did not want to override the parent's method.
-
Luis Martin over 11 years@Awemo: The examples explain about overriding. I don't want to override. Regarding the second example, I wouldn't have ever used $this to call the parent's method inside the overriden method. Check this modified example from the ones you provided: codepad.org/EkHXwrHs
-
Sherif over 11 years@Awemo they both go directly to the parent in the event the child does not declare the method. Your point was understood though I just wanted to clarify on the technicality I spotted in your information. Sorry, this is me being a pedantic PHP developer :)
-
Luis Martin over 11 yearsexcuse me if I seem to be a little slow :) , but I'm not sure if I understood your explanation, since your example clearly shows that both ways would do the just same, but I think you're not saying which one should be the proper way. If I'm not wrong, you said that since I will not override myMethod(), I should declare it final within the parent class, and what then?
-
Wesley Murch over 11 yearsIt's not just a matter of taste, Ed Heal is wrong about that.
-
Sherif over 11 yearsI did, by stating that they both do different things
parent::method()
means always call on the parents method regardless of whether or not the instance object defines it.$this->method()
means always call on the method if it's defined in the instance or forward the call to its parent until it is either found or a fatal error of undefined object is reached. I also explained in the last paragraph that if you declare the method as final you will always be fine when calling $this->myMethod() from object context. I'm not sure how much more clear I could have made that. -
Luis Martin over 11 yearsOk, so, look at the code I added on the EDIT part. That's the code in which my question came up. Should I declare final protected function validate_form($validation) in the parent class, and use $this->validate_form(...); in the child class?, do I use parent::validate_form(...) in the child class? drop the final keywork? because either way works in my case. In fact I'm not using more than one level of inheritance. Maybe you mean it would be convenient for 2 or more level exetnsion?
-
Luis Martin over 11 yearsAnother point of view in my question: if I'm not wrong, doing parent::validate_form() without redeclaring this method within the child class would technically be faster, since the php engine wouldn't have to search for the inherited method, or declaring the parent's method to be final and using $this->validate_form() would also forward directly to the parent class.... what a mess! hehe I don't think there is much difference at the end! :)
-
Sherif over 11 yearsI'm not sure how much more I could possibly repeat myself here... If you do not want the method to be overridden in the children then do the following two things 1) declare the parent method as final, 2) simply call $this->method from all and any extending classes when in object context. If you do not declare the parent method as final you must call parent::method() to ensure you are calling the parent method. However, I noted the caveats of multilevel inheritance for you above with an example of what happens if one of the parents overrides the method.
-
Sherif over 11 yearsPHP will do the right thing. Do not make these decisions based on which is faster, because they do different things something that doesn't do what you want really really fast is pretty useless in the face of something that does do what you want regardless of how fast or slow it maybe. In this case the performance differences are actually quite negligible.
-
Luis Martin over 11 yearsI take your advice GoogleGuy. Thank you!