blog

PHP Traits: Multiple Inheritance Revisited

When I first wrote about my hacky TypeScript multiple inheritance implementation that destroyed a codebase, I included a small (emphasis on small) section about multiple inheritance in C++, mostly as a joke about how complicated my TypeScript solution was becoming. I was, however, unaware of PHP's approach to the concept, so I thought I should write an addendum to that piece.

PHP, while primarily functional, does boast object-oriented capabilities that have only improved over time. One of these (added in PHP 5.4!) is Traits, which allow you to compartmentalize code into modules added arbitrarily to classes. Traits are essentially small classes that are not instantiable and are added with a use statement within the class body as opposed to the extend statement.

Type Checking

Traits allow PHP classes to reuse code, but do not allow them to be treated as equivalent in type-sensitive scenarios. While an inherited class can be specified as a type for a function parameter (in PHP 8 at least) to allow any subclasses to also be passed, traits do not share this behavior. This makes them better for sharing behaviors rather than signatures if one wants to use static typing, as opposed to a traditional multiple-inheritance composition setup that allows static typing. This lessens the usefulness of the new PHP 8.3 class and trait function typing (as well as is_a type checking) as one cannot allow classes using a given trait to be passed as an argument.

<?php
trait Foo {
    function doit() {
        echo "foo";
    }
} 
class Bar {
    use Foo;
}
function baz(Foo $param) {
    $param->doit();
} 

baz(new Bar()); // Typeerror :(

Given PHP's function typing is already somewhat complex, supporting union and intersection typing, they could easily remedy this by allowing a new type of decorator to apply traits, or adding them to union support: for instance, function foo(@MyTrait) $param){} or similar.


Leave a Reply

All comments undergo moderation before being shown.