Conjuring Functionality Mystique with Anonymous Classes
Anonymous classes are classes without a name. If you’ve been following this article series, this shouldn’t be that foreign of a concept to you. Think back on anonymous functions.
https://blog.devgenius.io/php-7-x-p39-anonymous-functions-75f6f99fa571
An anonymous class can be assigned to a variable or be passed as an argument. They use the keyword Class and are instantiated with the new keyword. They can pass constructor arguments, inherit from their parent class, and implement interfaces. In other words, they can do everything that a regular class can do.
Recap: Review the code from the previous article.
https://github.com/dinocajic/php-youtube-tutorials/tree/master
We ended by creating the following test file and passing different vehicles to the Driver class.
<?php
// Object Arguments
require_once("Lamborghini.php");
require_once("Ferrari.php");
require_once("Driver.php");
$lamborghini_diablo = new Lamborghini(1999, "Lamborghini", "Diablo");
$ferrari_f355 = new Ferrari(1996, "Ferrari", "F355");
$dino = new Driver( $ferrari_f355 );
$dino->drive();
$harrison = new Driver( $lamborghini_diablo );
$harrison->drive();
Both the Lamborghini and the Ferrari classes are just empty classes that extend the Car class.
<?php
require_once("Car.php");
class Lamborghini extends Car {
}
<?php
require_once("Ferrari.php");
class Ferrari extends Car {
}
The Car class extends the Vehicle class. Both the Ferrari and the Lamborghini classes inherit properties and methods from the Car and Vehicle classes. The Lamborghini and Ferrari classes were instantiated in our code above and passed to the Driver class.
Considering that both the Lamborghini and Ferrari classes are just blank, we could easily take advantage of anonymous classes. The following syntax is used to generate an anonymous class.
$obj = new Class() { ... }
You actually do use the Class keyword. We wouldn’t specify Lamborghini or Ferrari here. It doesn’t matter, it’s anonymous. Let’s tackle our $lamborghini object.
$lamborghini_diablo = new Lamborghini(1999, "Lamborghini", "Diablo");
We passed three arguments, so our syntax should look like this.
$obj = new Class($x, $y, $z) { ... }
I know. Jumping right into the more advanced stuff. We’re doing this so that we can transform our example. It’ll make perfect sense soon if not already.
Our Lamborghini class also extends Car, so we can mimic that too with our syntax.
$obj = new Class($x, $y, $z) extends ClassName { ... }
Now that we have the syntax down, let’s see how we can replace the $lamborghini_diablo and $ferrari_f355 object instantiations.
<?php
require_once("Car");
require_once("Driver");
$lamborghini_diablo = new Class(1999, "Lamborghini", "Diablo") extends Car {};
$ferrari_f355 = new Class(1996, "Ferrari", "F355") extends Car {};
$dino = new Driver( $ferrari_f355 );
$dino->drive();
$harrison = new Driver( $lamborghini_diablo );
$harrison->drive();
Running the code again will yield the exact same results. It may look a little strange since we’re passing arguments to the anonymous class constructor, but remember that this gets passed to the Car class constructor. The anonymous class has no constructor so it’s just shifted up the inheritance chain. The Car class does accept three required arguments.
Next up, why do we need to assign the anonymous class to the $lamborghini_diablo variable and then pass that variable to the Driver constructor? We could just pass the anonymous class directly to the constructor.
<?php
require_once("Car");
require_once("Driver");
$dino = new Driver( new Class(1996, "Ferrari", "F355") extends Car {} );
$dino->drive();
$harrison = new Driver( new Class(1999, "Lamborghini", "Diablo") extends Car {} );
$harrison->drive();
There’s no difference. We were creating an object and assigning it to a variable. We’re just skipping the variable assignment step and sending the anonymous class as an argument. If you’re still having a difficult time visualizing this, look at something simpler.
function add($a, $b) {
return $a + $b;
}
$a = 3;
$b = 5;
echo add($a, $b);
Why do we need to assign 3 to $a and 5 to $b. We could just pass those as arguments to the add function.
function add($a, $b) {
return $a + $b;
}
echo add(3, 5);
Similar concept.
I know when you read through anonymous classes online, this seems like a super complex subject. You may be asking yourself, “that’s it?” Yep. That’s it. Nothing more complicated than what we just looked at.
Let’s look at one final example to solidify this concept. We’re going to create a method inside of our anonymous class and then call it from our Driver class.
Looks scary I know, but it’s really not. Let’s walk through the code.
- A new method was added to the Driver class called whatAmIDriving(). The method will echo out whatever the $car->getDriverVehicle() method returns. Remember, we’re going to assign an object to the $car property and that $car property will have access to all of the object methods, including this new method called getDriverVehicle().
- A new Driver object is instantiated and is assigned to the variable $dino.
- During instantiation of the Driver object, an anonymous class is passed to the Driver object.
- This anonymous class extends the Car class and has one method. The method name is getDriverVehicle(). This is where it might confuse some. The method is referencing $this->year, $this->make, and $this->model. Remember that we’re extending the Car class.
- That anonymous class, with its new method, is assigned to the $car property and we can call any methods inside of the $car object, including our newly passed getDriverVehicle() method.
Walk through it a couple of times and it will make sense. If you still need assistance, reach out to me and I would be more than happy to try a different explanation.
CONVEYING INSIGHTS BY PASSING OBJECTS AS MESSENGERS
We’ve looked at passing numerous different data types as arguments to methods, but we haven’t looked at passing objects as arguments to methods.
Conjuring Functionality Mystique with Anonymous Classes
Anonymous classes are classes without a name. If you’ve been following this article series, this shouldn’t be that foreign of a concept to you. Think back on anonymous functions.
STAMPING ENDURING MARKS ON CODE’S PATH WITH ‘FINAL’
The final keyword can be prefixed to methods and classes. If you prefix a method in the parent class, and the child class inherits the methods from the parent, the final keyword prevents the child class from overriding that method.