Access protected method from child class in PHP

10,216

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.

  1. Accessing with parent keyword
  2. Accessing with this leads to unexpected behaviour.

Hope I could be of help.

Share:
10,216

Related videos on Youtube

Luis Martin
Author by

Luis Martin

Updated on August 20, 2022

Comments

  • Luis Martin
    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
      Luis Martin over 11 years
      You mean none of them are considered a bad practice?
    • Wesley Murch
      Wesley Murch over 11 years
      Technically 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
      Wesley Murch over 11 years
      What 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
      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
      Wesley Murch over 11 years
      But, you are overriding myMethod in your example, and calling the parent myMethod in your child myMethod. 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
      Peter Adrian over 11 years
      Actually, 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
    Ed Heal over 11 years
    He did mention "If I don't need to override it in the child class"
  • Wesley Murch
    Wesley Murch over 11 years
    But of course he's calling myMethod from the child method myMethod which makes the question very confusing.
  • v0d1ch
    v0d1ch over 11 years
    Well if you don't override it you cant call it with $this right ?
  • v0d1ch
    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
    v0d1ch over 11 years
    Yea, Yea I know don't rub it in :)
  • Luis Martin
    Luis Martin over 11 years
    Right 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
    v0d1ch over 11 years
    Ed Heal also said just a matter of taste. I prefer $this
  • Sherif
    Sherif over 11 years
    That 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 that self does not allow for LSB (Late Static Binding) which could get you in some trouble as well ;)
  • Awemo
    Awemo over 11 years
    I 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
    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
    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
    Luis Martin over 11 years
    excuse 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
    Wesley Murch over 11 years
    It's not just a matter of taste, Ed Heal is wrong about that.
  • Sherif
    Sherif over 11 years
    I 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
    Luis Martin over 11 years
    Ok, 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
    Luis Martin over 11 years
    Another 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
    Sherif over 11 years
    I'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
    Sherif over 11 years
    PHP 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
    Luis Martin over 11 years
    I take your advice GoogleGuy. Thank you!