Search icon
Subscription
0
Cart icon
Close icon
You have no products in your basket yet
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Mastering PHP 7

You're reading from  Mastering PHP 7

Product type Book
Published in Jun 2017
Publisher Packt
ISBN-13 9781785882814
Pages 536 pages
Edition 1st Edition
Languages
Author (1):
Branko Ajzele Branko Ajzele
Profile icon Branko Ajzele

Table of Contents (24) Chapters

Title Page
Credits
About the Author
About the Reviewers
www.PacktPub.com
Customer Feedback
Preface
1. The All New PHP 2. Embracing Standards 3. Error Handling and Logging 4. Magic Behind Magic Methods 5. The Realm of CLI 6. Prominent OOP Features 7. Optimizing for High Performance 8. Going Serverless 9. Reactive Programming 10. Common Design Patterns 11. Building Services 12. Working with Databases 13. Resolving Dependencies 14. Working with Packages 15. Testing the Important Bits 16. Debugging, Tracing, and Profiling 17. Hosting, Provisioning, and Deployment

Anonymous classes


Instantiating objects from classes is a pretty straightforward action. We use the new keyword, followed by a class name and possible constructor parameters. The class name part implies the existence of a previously defined class. Though rare, there are cases where classes are only used during execution. These rare cases make it verbose to force a class definition separately when we know that the class is only being used once. To address this verbosity challenge, PHP introduced a new functionality called anonymous classes. While the concept of anonymous classes has been around for quite some time in other languages, PHP only got to it in the PHP 7 release.

The syntax of anonymous classes is pretty straightforward, which is as follows:

$obj = new class() {};
$obj2 = new class($a, $b) {
   private $a;
   private $b;
   public function __construct($a, $b) {
     $this->a = $a;
     $this->b = $b;
   }
};

We use the new keyword , followed by the class keyword, followed by optional constructor parameters, and finally the body of the class packed in curly braces. Both objects are instantiated as a class@anonymous type. The functionality of objects instantiated through anonymous classes is no different from those instantiated via named classes.

Compared to named classes, anonymous classes are pretty much equal, in that, they can pass contractor parameters, extend other classes, implement interfaces, and use traits. However, anonymous classes cannot be serialized. Trying to serialize an instance of an anonymous class, as shown in the following code snippet, throws a fatal Serialization of class@anonymous is not allowed… error.

There are few other caveats to keep in mind when using anonymous classes. Nesting an anonymous class within another class hides the private and protected methods or properties of that outer class. To circumvent the limitation, we can pass the outer class' private and protected properties into an anonymous class constructor, as follows:

interface Salary {
      public function pay();
   }

   trait Util {
      public function format(float $number) {
         return number_format($number, 2);
      }
   }

   class User {
      private $IBAN;
      protected $salary;
      public function __construct($IBAN, $salary) {
         $this->IBAN = $IBAN;
         $this->salary = $salary;
      }

      function salary() {
       return new class($this->IBAN, $this->salary) implements Salary {
         use Util;
         private $_IBAN;
         protected $_salary;

         public function __construct($IBAN, $salary) {
            $this->_IBAN = $IBAN;
            $this->_salary = $salary;
         }

        public function pay() {
           echo $this->_IBAN . ' ' . $this->format($this->_salary);
        }
     };
   } 
 }
 $user = new User('GB29NWBK60161331926819', 4500.00);
 $user->salary()->pay();

In this strip down User class example, we have a salary method that returns an anonymous class. To showcase the more robust use of anonymous classes, we make it implement the Salary interface and use the Util trait. The Salary interface forces the anonymous class to implement the pay method. Our implementation of pay method requires IBAN and salary member values from the outer class. Since an anonymous class does not allow access to private and protected members of the outer class, we pass those through anonymous class constructors. While the overall example certainly does not reflect notions of a good class design, it does showcase how to bypass the member visibility limitation.

There is also an option for an anonymous class to fetch the private and protected members of the outer class by extending the outer class itself. However, this requires the anonymous class constructor to properly instantiate the outer class; otherwise, we might end up with a warning, such as a missing argument, for User::__construct().

Even though they are namelessly defined, anonymous classes still get an internal name. Using the core PHP get_class method on an instance of an anonymous class, gets us that name, as shown in the following examples:

class User {}
class Salary {}

function gen() {
  return new class() {};
}

$obj = new class() {};
$obj2 = new class() {};
$obj3 = new class() extends User {};
$obj4 = new class() extends Salary {};
$obj5 = gen();
$obj6 = gen();

echo get_class($obj); // class@anonymous/var/www/index.php0x27fe03a
echo get_class($obj2); // class@anonymous/var/www/index.php0x27fe052
echo get_class($obj3); // class@anonymous/var/www/index.php0x27fe077
echo get_class($obj4); // class@anonymous/var/www/index.php0x27fe09e
echo get_class($obj5); // class@anonymous/var/www/index.php0x27fe04f
echo get_class($obj6); // class@anonymous/var/www/index.php0x27fe04f

for ($i=0; $i<=5; $i++) {
  echo get_class(new class() {}); // 5 x   
    class@anonymous/var/www/index.php0x27fe2d3
}

Observing these outputs, we see that the anonymous classes created in the same position (function or a loop) will yield the same internal name. Those with the same name return true for the equal (==) operator and false for the identity operator (===), an important consideration in order to avoid potential bugs.

Support for an anonymous classes opens a door to some interesting use cases, such as mocking tests and doing the inline class overrides, both of which, when used wisely, can improve code quality and readability.

You have been reading a chapter from
Mastering PHP 7
Published in: Jun 2017 Publisher: Packt ISBN-13: 9781785882814
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}