Hello list,

currently, the default mode for attributes is to create a new class.
For general initializers, with
https://wiki.php.net/rfc/new_in_initializers we get the option to call
'new C()' for parameter default values, attribute arguments, etc.

Personally I find class construction to be limiting, I often like to
be able to use static factories instead.
This allows:
- Alternative "constructors" for the same class.
- A single constructor can conditionally instantiate different classes.
- Swap out the class being returned, without changing the factory name
and signature.

In fact, static factories for initializers were already mentioned in
"Future Scope" in https://wiki.php.net/rfc/new_in_initializers.
However this does not mention static factories for the main attribute object.

For general initializers this is quite straightforward.
For attributes, we could do this?

// Implicitly call new C():
#[C()]
# Call the static factory instead:
#[C::create()]

So the only difference here would be that in the "traditional" case we
omit the "new " part.

We probably want to guarantee that attributes are always objects.
We can only evaluate this when somebody calls ->newInstance(), because
before that we don't want to autoload the class with the factory. So
we could throw an exception if the return value is something other
than an object.
I was also considering to require an explicit return type hint on the
factory method, but again this can only be evaluated when somebody
calls ->newInstance(), so the benefit of that would be limited.

The #[Attribute] annotation would allow methods as target.

Reflection:

::getArguments() -> same as before.
::getName() -> returns "$class_qcn::$method_name".
::getTarget() -> same as before.
::isRepeated() -> This is poorly documented on php.net, but it seems
to just look for other attributes with the same ->getName(). So it
could do the same here.
::newInstance() -> calls the method. Throws an error if return value
is non-object.

we could add more methods like ReflectionAttribute::isClass() or
ReflectionAttribute::isMethod(), or a more generic ::getType(), but
these are not absolutely required.

We could also allow regular functions, but this would cause ambiguity
if a class and a function have the same name. Also, functions cannot
be autoloaded, so the benefit would be small. I'd rather stick to just
methods.

-----

Side note: I think "attributes" is a really poor name for findability.
But this ship has sailed.

-----

Cheers
Andreas

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

Reply via email to