Home > OS >  How to type hint a trait when using the trait to realize multi-inheritance?
How to type hint a trait when using the trait to realize multi-inheritance?

Time:07-30

Multi-inheritance is realized by using trait, but the type of parameters cannot be limited. For example, the following example

trait T{
    function t(){
        echo 'trait';
    }
    // Omit many other codes
}

class B{ } // Assume that B is a third-party module

class C extends B{ // Assume that C must inherit the module B
    use T;
}

// Some functions in some classes in the following client code may need to use several methods in T, like the following.
function f(T $t){ // Type-hinting for the trait T, but there is a problem
    $t->t();
}

f(new C);

Sandbox test found an error Fatal error: Uncaught TypeError: f(): Argument #1 ($t) must be of type T, C given

If f(T $t) is changed to f(C $t) or f($t), it will be fine, but this is not what I want. It won't work if the trait is changed to an interface, because the function body can't be written in the interface. It won't work if the trait is changed to a class, because C has already inherited one class and can't inherit another. What can we do to realize multi-inheritance and restrict types?

CodePudding user response:

Traits are not classes, we just use them to reuse some code in multiple classes. You may create an interface and use it as the common type in your method.

CodePudding user response:

PHP doesn’t support multiple inheritance so it uses traits and interfaces to get around that limitation. PHP does not treat a trait as a class (as you have experienced).

I believe you're trying to force PHP to do something it just can't do. Traits are used as "vehicle" or an independent package to augment, expand, and inject some functionality into classes when the code for that functionality doesn't belong in a parent class, or in an interface.

For example, I've created database access traits to give specific classes the ability to read and write data, and once I wrapped Guzzle functionality into a trait so some classes could make API calls.

You can argue whether these are good examples, or whether these specific examples should have been traits at all (and I might agree). But the point is, traits are generally used to add something that shouldn't be in a parent class. In my cases I chose to add them as traits because it seemed like way too much code to add to a parent class when most of the children were not going to be using those methods, and because multiple classes needed access to that functionality.

In your case,

function f(T $t){ $t->t(); }

would be,

function f(C $c){ $c->t(); }

because C is using T and t() is a method in T.

  • Related