Inheritance vs. Composition -- PHP 5.4 Traits discussed as well

[QUOTE=ServerStorm;5037468]@guido2004
Maybe we should start a new thread with an example/description of object composition with comments of when to choose over inheritance and then link the inheritance to this thread. Thoughts?[/QUOTE]

Not a bad idea at all. And definitely worthy of discussion, because PHP 5.4 brings with it traits

Generally speaking, inheritance refers to vertical inheritance. That is, each class derives from one and only one other, and so inheritance leads to classes that stack upon one another as layers of a cake. The idea goes that you proceed from the general to the specific, from the abstract to the concrete. The limit of this approach is behaviors that need to be shared between two objects.

Object composition comes in two forms. The first is to have behavior packages locked into classes of their own, and then have those classes passed to the constructors of any class needing to use those packages. The largest problem here is privacy. The object package has no real ability to interact with the host object that is using its methods. There are work arounds, but they have problems of their own.

Both object composition and inheritance make use of interfaces. Interfaces provide maps to object behaviors. If an object claims to implement an interface, it must fulfill the instructions of the interface. The problem with interfaces is simply this, what if the implementation code of the method is not going to change (or change much) between objects, even though they have disparate inheritance trees? A lesser but still significant problem is that PHP doesn’t give a mechanism for interfaces to require a function to return specific data types - though there is an RFC for this purpose.

PHP 5.4 adds traits in an attempt to address this problem. Traits provide a way to fulfill interface requirements while having the implementation code in one place. Traits also allow for multiple inheritance.

This is very powerful, and with such great power comes considerable responsibility, because the door this opens can rapidly go awry if you don’t proceed with a plan (if you do proceed with a plan though you can get some extremely tight code).

Here’s a simple trait… one that makes the protected members readable (but not writable)


trait ReadMe {
  public function __get( $var ) {
    if (isset($this->$var) {
      return $this->$var;
    } else {
      trigger_error("Attempted access to non-existent property $var in " . __CLASS__, E_USER_NOTICE);
      return null;
    }
  }
}

class PhotoPose {
  use ReadMe;
  protected $smile = 'cheese';
}

$pose = new PhotoPose();
echo $pose->smile; // 'cheese';
echo $pose->laugh; // nothing typed.  Notice outputted if error reporting is set to return notices.

We can be more stringent if we wanted and throw an exception if a non-existent property is accessed, but throwing an error is more in line with PHP’s normal behavior.

Well, I’m tired and will continue with this later, but this should get us started.

Hi Michael,

Excellent start.

I was trying to pull past discussion regarding this (as there are some good ones, but had the nagging suspicion that new behavior in php 5.3+ would change the discussion.

The general mantra is “favour composition over inheritance” this idea is nicely discussed in this http:// http://www.sitepoint.com/forums/showthread.php?568744-When-to-use-inheritance&p=3945208#post3945208 sitepoint thread and specifically kyberfabrikken post within this thread of http://www.sitepoint.com/forums/showthread.php?568744-When-to-use-inheritance&p=3945208&viewfull=1#post3945208 where he amongst other things makes a case for that object behaviour can not be set at run-time and that with inheritance there is a lack of clarity versus compositional code, while being more verbose, is very clear in what it is doing.

So Michael are you saying that with PHP 5.4; Traits and Multiple Inheritance that composition in PHP should no longer be favoured? If even with the OOP improvements in PHP 5.4, when would you use composition over Inheritance?

Thanks for kicking this discussion off!
Regards,
Steve

I’ve personally never favored composition because of the amount of dependency tracking it requires to remain stable. Also, the binding issues are not insignificant - the child object that holds the behaviors either has to have access to the members of the host object or those methods must remain public. In most frameworks I’ve seen this latter tact is what is done, which I find troublesome. Protected methods and members allow us to increase the isolation of a class. In order not to get killed by the complete graph problem we need isloation. Design patterns, by their nature, create isolation between code areas to make those blocks easier to manage.

The multiple inheritance that traits offer also provide a powerful and compelling alternative to object composition. Now the traits can have access to the protected or even the private values of the host class. This is a two way trade for better or worse - the protected methods of the trait are exposed to the rest of the implementing class.

I imagine that roughly half the current use cases of object composition out there will be better served with traits. I however haven’t had enough time to investigate and form concrete examples.

I will say this, traits have few to any restrictions on how they are meshed to classes. This can create code maintenance headaches. For example, you can (and sometimes will need) to alias a trait’s function name when it is added to a class. This is going to get ugly real fast if some self control isn’t exercised. Although PHP places no stricture on what can and cannot be aliased, my instincts tell me that you should probably never alias a public method of a trait. The fact that an object implements a trait will be picked up by the instanceof operator. From outside the class you can quickly create a headache for the outside developer by changing expected external facing function names and properties around.

The largest game changer about traits is they remove the need to build large class inheritance pyramids. Instead utility object methods can be spliced in on demand.

Also, through use of the factory pattern you can use traits to do object composition. For example, say you have a database factory and you ask it for a database. There are two database objects available - the standard one and one that has the traits for debuging grafted on. The factory can return the one appropriate to the current mode of operation. We could have done this with a straight descendant, but we’d have to repeat the debug methodology in every class. Object composition would have to create a debug object and pass that as a parameter to the database object, which would then carry ‘orphan’ code around even when the system isn’t in debug mode to deal with that case. It works, but it’s not as efficient.

Overall though, traits scare me to be honest. I get their syntax, goals and how they can be used. But they have a lot of potential for misuse, and 4 to 6 years from now we’re all going to be wading through the results of that misuse unless we work together as a community to get our heads around them and counsel the less experienced on the pitfalls that await.

Multiple inheritance isn’t supported in Java for a reason - it’s very easy for it to become a muddled mess. It’s a bear to debug if you aren’t careful and, I imagine that in a compiled language it can be a bear to implement.

@Michael Morris

Thank you for taking the time to so clearly point out the possibilities, the risks and thoughts of moving forward with this topic!

I would like to invite any other forum members to ask questions even if they seem basic. Know one will judge you, we want to use these type of posts to provide better understanding to those that are thinking about starting OOP, or looking at improving on their OOP skills.

Michael I am going to mull over your comments and will hopefully have something meaningful to say/ask tomorrow.

Thanks,
Steve