See https://wiki.php.net/rfc/named_params and scroll down to call_user_func_array().
call_user_func_array() is used by Rules core to invoke conditions/actions, which each define their own set of context variables that need to passed in as parameters.
Core dealt with this in #3174022: call_user_func_array() and named arguments in PHP 8. I will roll a patch for this later today.
| Comment | File | Size | Author |
|---|---|---|---|
| #20 | updated-rules-condition-base.patch | 548 bytes | yan.jaunky |
| #19 | updated-rules-action-base.patch | 521 bytes | yan.jaunky |
Issue fork rules-3210303
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
tr commentedComment #3
tr commentedComment #5
tr commentedCommitted #3 with the coding standards problem fixed.
Comment #6
jonathan1055 commentedHi TR,
I've looked at the two links you gave in the summary, and then looked at the commits you have made. I must be missing something as I can't see the connection between renaming the variables $account to $user, $entity_type to $type and $pos to $position and the original
call_user_func_array()change. Are those variable names used later, or are they now protected names or something?Comment #7
tr commentedPHP 8 introduced a new "named parameters" syntax.
If you define a function
myfunction($one, $two, $three), in addition to invoking it like$result = myfunction(1, 2, 3);, PHP 8 now allows you invoke it like$result = myfunction(one: 1, two: 2, three: 3);. Note that the name of the formal argument is used as a prefix to the value. If this syntax is used, then it is no longer necessary to pass the values in the same order they were defined. Thus, another valid and equivalent way to call this is$result = myfunction(two: 2, three: 3, one: 1);. PHP will match the names of the arguments and deliver them to the function in the correct order - when using this syntax the order of the values being passed no longer matters.Another way to invoke this function is to use
$array = [1, 2, 3]; $result = call_user_func_array('myfunction', $array);. In Rules we do this to call thedoExecute()method of conditions and actions because the arguments to thedoExecute()function depend on the context variables defined in the annotation for those conditions and actions. We put all the context variables into an array indexed by the name of the context variable then pass that array as the second argument tocall_user_func_array().The problem arises when the name of the context variable in the annotation doesn't match the name of the variable used in the definition of
doExecute(). In PHP 8,call_user_func_array()will now internally use the named parameter syntax to call the function, so if we pass an array like$array = ['uno' => 1, 'dos' => 2, 'tres' => 3];then$result = call_user_func_array('myfunction', $array);will now fail because instead of passing the array arguments in order it will try to use the keys of the array to match the function's arguments. Because there is no formal argument$uno(we called it$one) PHP will complain about an unknown named argument$uno.What this means in concrete terms, using the UserIsBlocked condition as an example, is that if we define a context variable 'user' in the annotation, then
doExecute()now MUST have an argument with the variable name$user- nothing else is allowed. We were using$accountfor the name of the variable indoExecute(), and that was and is perfectly valid in PHP 8 and previous versions of PHP UNLESS you usecall_user_func_array(), in which case the context variable name needs to match exactly the variable name used withindoExecute().In the case of 'pos' I changed the context variable name instead of the variable name in
doExecute()because the full name is more descriptive and usable, and abbreviating 'position' doesn't save anything.Comment #8
jonathan1055 commentedThank you so much for taking the trouble to explain all that. It is really helpful, not just for me, but for others who may be discovering the same problems.
Comment #9
liam morlandThe could also be fixed by passing the second parameter to call_user_func_array() through array_values() so that it doesn't have keys that would be treated as named parameters.
Comment #11
glynster commented@TR we just upgraded some of our sites to PHP8 and came across this error even with the latest rules:
"drupal/rules": "3.x-dev@dev",
Patch
"Rules registers no listeners on rare occasions": "https://www.drupal.org/files/issues/2022-01-31/2816033-102-no-listeners....",
Not sure if I am doing the right thing by adding a comment here or if I need to create a new case.
Comment #12
tr commented@glynster: Are you using actions or conditions provided by some module other than Rules? Those may not be PHP 8 compatible.
Comment #13
glynster commentedYes we are using your other module and rules flag:
"drupal/tr_rulez": "1.x-dev@dev",
"drupal/rules_flag": "1.0.x-dev",
"drupal/role_expire": "1.x-dev",
That said I have narrowed it down to core Rules (I think). Here is the rule that is causing the issue:
I wonder if it is related to role_expire_set_expire_time
Comment #14
glynster commentedWhen I remove this action from the above rule it works:
Comment #15
tr commentedThat problem is with the role_expire module - both of the actions in that module need to be modified to be compatible with PHP 8.1.
The needed change for those actions is what I described in #7:
That change is as easy as renaming the variable from $account to $user in doExecute().
That module should also really have some test cases so they can verify that it really works with all supported versions of PHP and core Drupal.
Comment #16
glynster commented@TR yup as always you were right. I am going to create a patch and add it to the role_expire issues. Thanks for pointing me in the right direction!
Comment #17
glynster commented@TR here is the case and patch: https://www.drupal.org/project/role_expire/issues/3265491#comment-14418022. Resolved the problem for us. Works on PHP7.4 and PHP8 <
Comment #19
yan.jaunky commentedHello,
I did a small update in the file RulesActionBase.php concerning call_user_func_array. It throws an exception Error : Unknown named parameter.
Comment #20
yan.jaunky commentedAnother update was done in RulesConditionBase.php
Comment #21
tr commentedThis issue was closed and fixed almost two years ago. There is nothing more that needs to be done here.