-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add #[NamedParameterAlias] attribute #6522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like useful functionality to have; the additional error handling and handling of edge cases should be possible to add.
Zend/zend_attributes.c
Outdated
void validate_namedparameteralias_attribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope) | ||
{ | ||
if (attr->argc != 1) { | ||
zend_error_noreturn(E_ERROR, "NameAlias::__construct(): Argument #1 ($alias) is required"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zend_error_noreturn(E_ERROR, "NameAlias::__construct(): Argument #1 ($alias) is required"); | |
zend_error_noreturn(E_ERROR, "NamedParameterAlias::__construct(): Argument #1 ($alias) is required"); |
--FILE-- | ||
<?php | ||
|
||
function test(#[NamedParameterAlias("bar")] $foo) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be more tests and checks in the implementation, e.g.
- Should invalid identifiers such as
NamedParameterAlias("some-name")
throw or be silently forbidden for invalid variadic arguments? - Should php warn/throw if using an alias for a parameter name that was already used? (
test(#[NamedParameterAlias("bar")] $foo = null, $bar = null)
) - Handling supporting more than one alias?
i | ||
); | ||
|
||
if (attribute && zend_string_equals(arg_name, Z_STR(attribute->args[0].value) )) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A complete implementation of this would support
- Supporting or forbidding multiple NamedParameterAlias values on a single parameter (EDIT: The RFC mentions that's still undecided, but my preference would be repeatable)
- Error checking - (1) check if there is at least one argument, (2) check if the type is a string, (3) possibly attempt to evaluate the argument if the type is IS_CONSTANT_AST and check for
EG(exception)
and return-1
- It may be useful to add some sort of bit flag to the function when compiling to indicate that there are parameter aliases to avoid the need to loop in cases
EXPECTED(*cache_slot == fbc)
doesn't always return early for, such as dynamic calls or polymorphism.
Also, it may be more efficient for the common case to loop over all arguments first and check arg_info->name, and only try to load the attributes in a separate loop if the first attempt failed (efficient for non-variadic functions, but not for variadic functions)
@@ -4354,6 +4355,21 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( | |||
*(uintptr_t *)(cache_slot + 1) = i; | |||
return i; | |||
} | |||
|
|||
if (fbc->common.attributes != NULL) { | |||
zend_attribute *attribute = zend_get_parameter_attribute_str( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like it'd be a bit more efficient to do this outside of this loop and find the parameters where attr->offset > 0
to avoid quadratic runtime - e.g. if there was a function with 20 parameters with attributes, it'd loop over all 20 of them just to find the ones at position i
, performing 400 operations
The index to use would be attr->offset - 1
static zend_attribute *get_attribute_str(HashTable *attributes, const char *str, size_t len, uint32_t offset)
{
if (attributes) {
zend_attribute *attr;
ZEND_HASH_FOREACH_PTR(attributes, attr) {
if (attr->offset == offset && ZSTR_LEN(attr->lcname) == len) {
if (0 == memcmp(ZSTR_VAL(attr->lcname), str, len)) {
return attr;
}
}
} ZEND_HASH_FOREACH_END();
}
return NULL;
}
ZEND_API zend_attribute *zend_get_parameter_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
{
return get_attribute(attributes, lcname, offset + 1);
}
what do you think of renaming it to just |
@beberlei Are you still planning on pursuing this RFC? |
@iluuu1994 realistically i do not have time at the moment, do you want to take over? |
Not personally. I'm closing stale PRs. And since named params have been introduced we've had little feedback about needing this feature so I'm not sure it's even necessary. Can this PR and RFC be closed? |
The sooner we add this functionality to allow a second alias name of a parameter when using the new "named parameters" feature, the better, because open source libraries will only be able to use this across versions when their minimum version includes this feature.
In the long term, open source code (closed source as well) will want the ability to a.) build APIs using named params b.) have the flexibility to refactor parameter names.
Addressing this need with an attribute would in my opinion be a good idea, because it requires very little code and only affects the code path of named params in a single isolated place.
RFC: https://wiki.php.net/rfc/named_parameter_alias_attribute