Autor wpisu: bastard13, dodany: 03.07.2014 00:23, tagi: design, oop
Autor wpisu: Wojciech Sznapka, dodany: 11.06.2014 21:57, tagi: oop, php
One of my favorite PHP interview questions, is: what is Type Hinting and why it’s important? Putting definition in one sentence, Type Hinting is a way to define type of parameter in function signature and it’s a sine qua non to leverage polymorphism. Because of dynamic typing in PHP, parameters don’t need to have type used. Also, by type here, I mean complex types (class, abstract class, interface, array, closure), not primitives like integer or double. So given the fact, that Type Hinting is optional and we don’t need to specify types of parameters passed to the method – why bother? Answer is easy: well prepared method signatures defines your model and are part of the “contract” that your code reveals to its consumers. It also prevents many silly errors and keeps codebase clean and coherent.
Now, if we all agree that Type Hinting is the way to go, what should we put in method signatures? We have few options: concrete class, base class or an interface. It all depends on situation. The most flexible way is the interface, because it’s small definition of object behavior and one class can implement multiple interfaces. Moreover, interfaces can be very easily mocked (by both mock tools, like Mockery or by mocks written by hand). All those adds up into great flexibility
Other option is to set class as type hint. You’re limited to this class instances and their descendants. Having multi-tier hierarchy graph, it’s often good idea to use a class in hierarchy near the root or even abstract class, which gives us possibility to apply method to whole graph of inheritance.
The least flexible way is to set a concrete class (near to final or not ever extended in current sytem). In such case you limit method only to serve for such objects, which is understandable, when method does a specific job.
Three options were presented above (interface, base class and concrete class). There’s one more, very important thing, that need to be kept in mind. Although PHP allows you to call methods outside the type that is defined for the method, you should never do that! It can lead to some bizarre errors and brakes Liskov Substitution Principle. Simply said: if you use a type in method’s signature, then it should rely only on this type, not it’s descendants (even we know about their existence), so you can substitute give type with new subclass without altering method body.
Have a look at possible violation of Liskov Substitution Principle:
class UserRepository extends \Doctrine\ORM\EntityRepository { public function findActiveUsers() { // do some query to retrieve the result return $activeUserCollection; } } // .. public function notifyActiveUsers(EntityRepository $repo) { if ($repo instanceof UserRepository) { $usersCollection = $repo->findActiveUsers(); } elseif ($repo instanceof ManagersRepository) { // .. do someting else } // do something with $usersCollection }
As we can see, type hinted method notifyActiveUsers internally relies on specific extension of EntityRepository. This breaks LSP and leads to unreadable model. Even worse situation can be following: