Re: [RFC] Attributes v2
| From: | Mike Schinkel | Date: | Wed, 11 Mar 2020 14:18:32 +0000 |
| Subject: | Re: [RFC] Attributes v2 | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-108979@lists.php.net to get a copy of this message | ||
> On Mar 10, 2020, at 5:03 PM, Benjamin Eberlei <kontakt@beberlei.de> wrote:
Thank you for answering again.
>>>> On Tue, Mar 10, 2020 at 9:41 PM Mike Schinkel <mike@newclarity.net> wrote:
>>>> -Mike
>>>> P. S. Did you see the question on interfaces?
>>> No I missed it. Attributes work on interfaces, but they are not inherited to parent
>>> classes. This is similar to how a class implementing an interface may have different docblocks. You
>>> can use the reflection api to get to interfaces from a class and check for their attributes there.
>>> For traits the attributes get copied into the using class.
>> I think you may have misunderstood my question. I was asking if using an interface we
>> could *require* a class to implement specific attributes. If yes that would be extremely valuable.
> I think i have answered the question that it exactly works like doc blocks, meaning that an
> interface cannot require a subclass to "implement" a docblock and an attribute also cannot
> do that.
Okay, I see the disconnect now. I was not realizing you were discussing attributes modifying
interfaces in the same way that doc blocks document interfaces. I was instead thinking that
interfaces could enforce which attributes are required.
From my use-case perspective, I have no need for attributes on interfaces or interface components,
but I have several use-cases for interfaces enforcing attributes be defined on my classes. (But I do
understand other's needs my differ.)
> In userland though, what you do with an interface requiring classes to implement attributes is
> up to you, so you can add this logic on top:
>
> interface ActiveRecord {}
> <<Table("bar")>>
> class Bar implements ActiveRecord {}
> class Baz implements ActiveRecord {}
>
> if ($object instanceof ActiveRecord) {
> $reflection = new ReflectionObject($object);
> $attributes = $reflection->getAttributes(Table::class);
>
> if (count ($attributes) == 0) {
> throw new \RuntimeException("Active Records are required to use the
> <<Table>> attribute");
> }
> // ..
> }
>
> The logic you implement on top of attributes are entirely up to your imagination, attributes
> itself don't enforce anything (other than they must be a class that exists).
But this non-enforcement aspect goes counter to the reason for interfaces.
From the first Google result[1] for "interfaces (programming)" it states: "An
interface is a programming structure/syntax that allows the computer to enforce certain properties
on an object (class)." You say that "what you do with an interface requiring classes to
implement attributes is up to you." But then I would ask, regarding interfaces, why do we not
that say "what you do with an interface requiring classes to implement methods is up to
you."
IOW, if interfaces cannot enforce the requirements of the "contract" why have interfaces?
Why not just use method_exisits() when we need to call a prescribed method?
What I am arguing is that an interface should be able to enforce ALL required implementation, not
just some.
Said another way, if I declare an interface to have a load_component(string $component_name) method,
why does it not make sense for that interface to also require the class to implement the
ComponentName($component_name) attribute on the class?
Note this is one of the many use-cases where I am currently using constants as pseudo-attributes
(because constants are easier to work with than doc blocks.) I am running into the problem that
people are creating components but forgetting to give the component a name, and then they either
waste time trying to figure out what they did wrong and just fail completely.
And I can provide several other use-cases if need be.
-Mike
P.S. Yes, I am sure one of you on the list will see this use-case and opine that I should be doing
it "better way." Please don't.
Yes, there are many architectures that one could choose, some better than others, but each
architecture has pros and cons and different people choose different architectures because they
evaluate those pros and cons different.
[1] https://www.cs.utah.edu/~germain/PPS/Topics/interfaces.html#:~:text=Interfaces%20in%20Object%20Oriented%20Programming,have%20a%20start_engine()%20action.