On Wed, Jan 5, 2022, at 2:35 PM, Chase Peeler wrote:

> First, I'm someone that mainly uses traits to implement the functionality
> defined in an interface. I think that's one of the best uses for them.
> However, I'm personally not a huge fan of overly restrictive things. For
> instance, while there are definitely some use cases for them, I need a
> REALLY good reason to justify making a property/method private instead of
> protected, or making a class final.

I am much the same.

> As such, I think this would be better if it didn't throw a fatal error.
> When you make it optional, however, I think you are left with something
> that can be handled with an attribute just as well as a new keyword:
> #[Expects('MyInterface')]
> trait foo { }
>
> However, there might be value in generating a notice/warning, and I think
> that would require a keyword, correct? (Not that up to speed on
> annotations). Another option might be two support two new keywords:
> requires and expects. The former would throw an error if the interface
> isn't implemented while the latter will throw a warning/notice/nothing.
>
> Another option (and I haven't thought about this one enough to decide if I
> like it) would be to have the expected interface automatically implemented
> in the using class. This would allow the trait to be written under the
> assumption it has access to the methods defined in the interface, and will
> then throw an error if any of the methods are not implemented in the using
> class:
>
> interface foo {
>   function a();
>   function b();
> }
>
> trait bar expects foo {
>    function c(){
>        return $this->a() + $this->b();
>    }
> }
>
> class baz {
>   use foo;
> }
>
> The above would throw an error since a() and b() are never implemented and
> baz is implementing the foo interface. You can currently get the same
> behavior if you define a() and b() as abstract in the trait. However, this
> doesn't give you the added benefit of utilizing the interface automatically
> within the type system. The more I think about it, the less I like this
> idea, since it doesn't require that much additional work to make the code
> clearer by explicitly implementing the interface on the class if you want
> it implemented. However, I'll go ahead and leave it here because it might
> help generate some other ideas.

I... still don't see any use in this annotation.  

Stepping back and ignoring the syntax for a moment, there's two different 
things here:

1. "This trait expects to be used in a class that has these other methods on 
it".
2. "This trait mostly/fully fulfills interface X, because it has methods a, b, 
and c."

For point 1, we already have that.  It's called abstract methods in traits.  
This is a solved problem that requires no further resolution.  At best it would 
be a shorthand to copying a few methods from an interface into the trait and 
sticking "abstract" in front of them.  I really don't see a need for that.

For point 2, that's mainly useful as a way to signal to other developers "hey, 
this trait has all but one method of the LoggerInterface, that's how you'd use 
it", and to signal static analyzers and refactoring tools the same thing so 
that they can be auto-updated if you tweak the interface.  I can see a use for 
point 2, and it would make my life a bit easier, but it's overall not high 
priority.

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to