The Difference Between self::, static:: and parent:: in PHP

  • The Difference Between self::, static:: and parent:: in PHP

    Sharing is Caring... Show some love :)

    In a lot of ways, PHP supports Object-Oriented Programming (especially using self::, static:: and parent:: in PHP).

    Seeing code written procedurally is becoming archaic and akin to finding dinosaur fossils in the Antarctic.

    We can all agree that writing code in an Object-Oriented way is better than writing it procedurally in a lot of ways.

    One of the fundamental tenets of an Object-Oriented Language is the concept of inheritance. A programming language must support inheritance to be seen as Object Oriented or maybe. 

    When writing classes in PHP, there will be times when we need to access methods defined in a class or a parent class within the class itself (rather than an instance of the class). 

    There are three such accessors that can be easily confused, and these are self::, static:: and parent:: in PHP. This article will describe these in detail to remove any ambiguity that might exist with these accessors.

    Before you dive in, check out the ultimate guide to Laravel 2021 to be up-to-date with Laravel Development.

    If you’re a backend developer or looking at delving into this career path, join other developers to receive daily articles on backend development that will boost your productivity.

    The self:: Accessor

    In order to picture this, let’s look at this line of code:

    <?php
    
    class Animal {
      public static function makeSound(){
        echo "Animal";
      }
      
      public static function vocalize() {
        echo self::makeSound(); 
      }
    }
    
    Animal::vocalize(); // Animal

    Looking at this example, it’s clear to see what the self:: keyword does. It’s used to refer to some other class member (property or method) within the same class. In our example, we refer to the makeSound() method within the vocalize method.

    Using self:: with Static and Non-static Class Members

    It’s important to note that the self:: keyword can be used for both static and non-static class members, but it throws an error when you try to access a non-static member from a static method, but not vice-versa. 

    Here are some code snippets to illustrate what this means:

    <?php
    
    class A {
      public function staticMethod() {
        echo get_class($this); 
      }
      
      public function otherStaticMethod() {
        self::staticMethod(); // This runs nicely. We can use self:: to access static methods from other static methods. 
      }
    }
    
    $a = new A();
    $a->otherStaticMethod(); // A

    In the sample above, we were able to call a static method from another static method using the self:: keyword. We could also do this by using the $this→ accessor.

    ALSO READ  How to upload images and videos to Cloudinary using Node.js

    As seen in the first code snippet, we can also access static methods from other static methods using the self:: keyword.

    <?php
    
    class A {
      public static function staticMethod() {
        echo "I am static"; 
      }
      
      public function nonStaticMethod() {
        echo "I am not static" . self::staticMethod(); // This works nicely.
      }
      
    }
    
    $a = new A();
    $a->nonStaticMethod(); // I am staticI am not static

    As seen in the example above, using a static method in a non-static method runs without problems.

    <?php
    
    class A {
      public function nonStaticMethod(){
        echo "I am non-static"; 
      }
      
      public static function staticMethod() {
        echo "I am static" . self::nonStaticMethod(); // Throws error: Non-static method cannot be called statically
      }
    }

    Using a non-static method in a static method causes an error. The same rules applied here also apply for static:: and parent:: in PHP.

    The parent:: Accessor

    The parent:: accessor is a rather specific and exact keyword. It refers to methods and properties in a parent class from the scope of a child class. Since the child class should override the properties by default, the accessor can explicitly refer to the parent class’s property. 

    It is also handy when both classes have properties with the same name. 

    <?php
    
    class A {
        public static function iAm() {
            return "A";
        }
    }
     
    // echo A::iAm();  // "A"
    
    class B extends A {
        public static function iAm() {
            echo "I am B. I come from " . parent::iAm();
        }
    }
    
    B::iAm(); // "I am B. I come from A"
    
    class C extends B {
        public static function iAm() {
            echo "I am C. I come from " . parent::class . "\n";
        }
        
        public static function iComeFrom() {
            parent::iAm();
        }
    }
    
    echo C::iAm(); // "I am C. I come from B"
    echo C::iComeFrom(); // "I am B. I come from A"

    The static:: Accessor

    In order to see this, let’s look at this snippet of code:

    <?php
    
    class Animal {
      public static function makeSound(){
        echo "Animal";
      }
      
      public static function vocalize() {
        echo self::makeSound(); 
      }
    }
    
    
    
    class Dog extends Animal {
      public static function makeSound() {
        echo "Dog";
      }
    }
    
    Dog::vocalize(); // This echoes "Animal". Shocker right?

    As seen in this example, using the self:: method causes some unexpected behavior when we extend the class using it. We would naturally expect the standard rules of inheritance that the makeSound() method should be overridden by the Dog class, but that isn’t the case. 

    ALSO READ  Motivational tips for backend developers

    This happens because when we use self::, we refer to the property class that used the self:: keyword, not any other child-class that extends it.

    Any method we access using the self:: keyword won’t get overridden by child classes. This may not be the behavior we expect.

    Take a break and check out the ultimate guide to Laravel 2021 to be up-to-date with Laravel Development.

    In PHP v5.3, a new feature called late static binding was implemented. The feature allows us to use the class named in the last call of a property. 

    This means when you use the static:: accessor, the method won’t be resolved until runtime, and during runtime, PHP will check for the last class that defines that method during the call. This would give us the kind of overriding mechanism we would expect. 

    Here’s an example:

    <?php
    
    class Animal {
      public static function makeSound(){
        echo "Animal";
      }
      
      public static function vocalize() {
        echo static::makeSound(); 
      }
    }
    
    
    class Dog extends Animal {
      public static function makeSound() {
        echo "Dog";
      }
    }
    
    Dog::vocalize(); // Animal
    
    class Husky extends Dog {
        public static function makeSound() {
            echo "Husky";
        }
    }
    
    Husky::vocalize(); // Husky

    As seen in the code sample above, using the static:: makes the makeSound method to be accessed at runtime on the class that overrides it. That is why accessing vocalize from the different classes behaves the way we would expect it to.

    Caveat with static:: when using with private non-static methods

    Private methods (and all properties) can only be accessed within the class that defines them. Parent classes can’t access them. When using the static:: accessor to access private static methods in child classes, it will fail. 

    ALSO READ  How to be a better software developer

    This is because when we access child (overridden) methods in child classes with the static:: keyword, we are trying to access them from the scope of the parent class. 

    If the overridden method is private, at runtime, it will try to access the method it finds from the last class calling it (which is private) from the scope of the parent class, and since the parent class can’t access that method because it’s private, the code will fail. 

    Here’s an example:

    <?php
    
    class A {
        private function foo() {
            echo "success!\n";
        }
        public function test() {
            static::foo();
        }
    }
    
    class B extends A {
       /* foo() will be copied to B, hence its scope will still be A and
        * the call be successful */
    }
    
    class C extends A {
        private function foo() {
            /* original method is replaced; the scope of the new one is C */
            echo "failure";
        }
    }
    
    $c = new C();
    $c->test(); // Fails because the private function's scope is in C and trying to access it from A will fail

    Using self::foo() or $this→foo() in class A would have worked without error, but it would echo “success!” and not “failure” because they would be referring to the foo() method in Class A, not the one in Class C. 

    Conclusion

    We learned a bit about inheritance and different accessors such as self::, static:: parent::, we can use when working with OOP in PHP. These accessors help us write clean code implementing the use of inheritance and polymorphism. 

    With these, we can build efficient data structures that make our projects easy to build, scale, and understand even if we hand off our code to others.

    We hope we’ve helped you learn something new, and if you did, let us know in the comments.

    Catch you in the next one!

    Start Learning Backend Dev. Now

    Stop waiting and start learning! Get my 10 tips on teaching yourself backend development.

    Don't worry. I'll never, ever spam you!

    Sharing is caring :)

    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99

    Comments