Internal error: Internal error: Multiple variants - use selectFromArgs() instead.
arnaudpfu opened this issue ยท 13 comments
I am using PHPStan via the last version of szepeviktor/phpstan-wordpress.
I get this error when I want to analyse my code.
-- -------------------------------------------------------------------------------------------------------------------------
Error
-- -------------------------------------------------------------------------------------------------------------------------
Internal error: Internal error: Multiple variants - use selectFromArgs() instead. in file /Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/core/AjaxSetup.php
Post the following stack trace to https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md:
#0 /Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/szepeviktor/phpstan-wordpress/src/HookCallbackRule.
php(83): PHPStan\Reflection\ParametersAcceptorSelector::selectSingle(Array)
#1 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnaly
ser.php(106): SzepeViktor\PHPStan\WordPress\HookCallbackRule->processNode(Object(PhpParser\Node\Expr\FuncCall),
Object(PHPStan\Analyser\MutatingScope))
#2 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Node/ClassStatemen
tsGatherer.php(98): PHPStan\Analyser\FileAnalyser->PHPStan\Analyser\{closure}(Object(PhpParser\Node\Expr\FuncCall),
Object(PHPStan\Analyser\MutatingScope))
#3 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(503): PHPStan\Node\ClassStatementsGatherer->__invoke(Object(PhpParser\Node\Expr\FuncCall),
Object(PHPStan\Analyser\MutatingScope))
#4 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(2460): PHPStan\Analyser\NodeScopeResolver::PHPStan\Analyser\{closure}(Object(PhpParser\Node\Expr\FuncCall),
Object(PHPStan\Analyser\MutatingScope))
#5 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(1462): PHPStan\Analyser\NodeScopeResolver->callNodeCallbackWithExpression(Object(Closure),
Object(PhpParser\Node\Expr\FuncCall), Object(PHPStan\Analyser\MutatingScope), Object(PHPStan\Analyser\ExpressionContext))
#6 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(555): PHPStan\Analyser\NodeScopeResolver->processExprNode(Object(PhpParser\Node\Expr\FuncCall),
Object(PHPStan\Analyser\MutatingScope), Object(Closure), Object(PHPStan\Analyser\ExpressionContext))
#7 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(357): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Expression),
Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#8 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(734): PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\Foreach_), Array,
Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#9 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(357): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Foreach_),
Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#10 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(518): PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\ClassMethod), Array,
Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#11 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(357): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\ClassMethod),
Object(PHPStan\Analyser\MutatingScope), Object(PHPStan\Node\ClassStatementsGatherer))
#12 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(596): PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\Class_), Array,
Object(PHPStan\Analyser\MutatingScope), Object(PHPStan\Node\ClassStatementsGatherer))
#13 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(357): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Class_),
Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#14 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(568): PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stmt\Namespace_), Array,
Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#15 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScope
Resolver.php(327): PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt\Namespace_),
Object(PHPStan\Analyser\MutatingScope), Object(Closure))
#16 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnaly
ser.php(175): PHPStan\Analyser\NodeScopeResolver->processNodes(Array, Object(PHPStan\Analyser\MutatingScope),
Object(Closure))
#17 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerComm
and.php(147): PHPStan\Analyser\FileAnalyser->analyseFile('/Users/arnaud/L...', Array, Object(PHPStan\Rules\LazyRegistry),
Object(PHPStan\Collectors\Registry), NULL)
#18 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evene
ment/src/Evenement/EventEmitterTrait.php(97): PHPStan\Command\WorkerCommand->PHPStan\Command\{closure}(Array)
#19 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/clue/ndjson-rea
ct/src/Decoder.php(110): _PHPStan_582a9cb8b\Evenement\EventEmitter->emit('data', Array)
#20 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evene
ment/src/Evenement/EventEmitterTrait.php(97): _PHPStan_582a9cb8b\Clue\React\NDJson\Decoder->handleData(Array)
#21 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/sr
c/Util.php(62): _PHPStan_582a9cb8b\Evenement\EventEmitter->emit('data', Array)
#22 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/evenement/evene
ment/src/Evenement/EventEmitterTrait.php(97):
_PHPStan_582a9cb8b\React\Stream\Util::_PHPStan_582a9cb8b\React\Stream\{closure}('{"action":"anal...')
#23 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/react/stream/sr
c/DuplexResourceStream.php(154): _PHPStan_582a9cb8b\Evenement\EventEmitter->emit('data', Array)
#24 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loo
p/src/StreamSelectLoop.php(201): _PHPStan_582a9cb8b\React\Stream\DuplexResourceStream->handleData(Resource id #3450)
#25 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/react/event-loo
p/src/StreamSelectLoop.php(173): _PHPStan_582a9cb8b\React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#26 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/src/Command/WorkerComm
and.php(107): _PHPStan_582a9cb8b\React\EventLoop\StreamSelectLoop->run()
#27 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console
/Command/Command.php(259):
PHPStan\Command\WorkerCommand->execute(Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Input\ArgvInput),
Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Output\ConsoleOutput))
#28 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console
/Application.php(868):
_PHPStan_582a9cb8b\Symfony\Component\Console\Command\Command->run(Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Input\A
rgvInput), Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Output\ConsoleOutput))
#29 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console
/Application.php(259):
_PHPStan_582a9cb8b\Symfony\Component\Console\Application->doRunCommand(Object(PHPStan\Command\WorkerCommand),
Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Input\ArgvInput),
Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Output\ConsoleOutput))
#30 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/vendor/symfony/console
/Application.php(157):
_PHPStan_582a9cb8b\Symfony\Component\Console\Application->doRun(Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Input\Arg
vInput), Object(_PHPStan_582a9cb8b\Symfony\Component\Console\Output\ConsoleOutput))
#31 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(124):
_PHPStan_582a9cb8b\Symfony\Component\Console\Application->run()
#32 phar:///Users/arnaud/Local
Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan.phar/bin/phpstan(125):
_PHPStan_582a9cb8b\{closure}()
#33 /Users/arnaud/Local Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/phpstan/phpstan/phpstan(7):
require('phar:///Users/a...')
#34 /Users/arnaud/Local Sites/other-builder-version/app/public/wp-content/themes/creatorem/vendor/bin/phpstan(115):
include('/Users/arnaud/L...')
#35 {main}
Child process error (exit code 1):
-- -------------------------------------------------------------------------------------------------------------------------
I found that this issue comes from this section of code
This code trigger the issue:
class Setup {
const ACTIONS = array(
'save_page_builder_data' => 'update_page_builder_data',
);
public static function init(): void {
foreach ( self::ACTIONS as $action => $method ) {
add_action( 'wp_ajax_' . $action, array( self::class, $method ) );
add_action( 'wp_ajax_nopriv_' . $action, array( self::class, $method ) );
}
}
public static function update_page_builder_data(): void {
// code here ...
}
}
And this code works:
class Setup {
public static function init(): void {
add_action( 'wp_ajax_save_page_builder_data', array( self::class, 'update_page_builder_data' ) );
add_action( 'wp_ajax_nopriv_save_page_builder_data', array( self::class, 'update_page_builder_data' ) );
}
public static function update_page_builder_data(): void {
// code here ...
}
}
How should I do to be able to use the first syntax ? I think that I need to tell to PHPStan than the values in the ACTIONS array corresponds to the name of method.
Hello Arnaud! ๐๐ป
I hope @johnbillion will reveal the cause of your error.
BTW The second version is more readable!
After looking at your intention I recommend my 3+1 hooking thingies :)
https://github.com/szepeviktor/Toolkit4WP/tree/master/src
Thanks for the report, I'll take a look.
Sorry @szepeviktor but I haven't found why your repo could help me. ๐
why your repo could help me.
Those 4 Hook
classes replace add_action
.
/**
* @hook one-of-the-four-ways
*/
public static function update_page_builder_data(): void {
... that is all you need.
You find minimal documentation in the source code.
@szepeviktor I prefer the first syntax because it enables me to set several ajax hooks in the same place :
class Setup {
const ACTIONS = array(
'save_page_builder_data' => 'update_page_builder_data',
'second_ajax_action' => 'second_ajax_handler',
'third_ajax_action' => 'third_ajax_handler',
'fourth_ajax_action' => 'fourth_ajax_handler',
// ...
);
public static function init(): void {
foreach ( self::ACTIONS as $action => $method ) {
add_action( 'wp_ajax_' . $action, array( self::class, $method ) );
add_action( 'wp_ajax_nopriv_' . $action, array( self::class, $method ) );
}
}
public static function update_page_builder_data(): void {
// code here ...
}
}
I find that way of doing cleaner.
I have read the codebase of your hooks. However I can't see when I can set the name of the method, that is why I don't see how I could achieve to do what I want in this way.
@arnaudpfu Okay! Here are all four examples.
// 1.
/**
* @hook wp_ajax_save_page_builder_data
*/
public static function update_page_builder_data(): void {
// and call self::hookMethods() method
// 2.
// call
HookConstructorTo::wp_ajax_save_page_builder_data(Setup::class, 10);
// if you want to instantiate a class in a hook
// 3.
// call
HookInitTo::plugins_loaded(Setup::class);
// if you want to instantiate a class and call its `init` method in a hook
// 4.
// call
self::lazyHookStaticMethod('wp_ajax_save_page_builder_data', [Setup::class, 'update_page_builder_data'])
// if you want to load a class and call a static method in a hook
@arnaudpfu Or the best way! You could match method names and AJAX action names!
public function __construct()
{
$classReflection = new ReflectionClass(self::class);
foreach ($classReflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
// Do not hook constructor.
if ($method->isConstructor()) {
continue;
}
\add_action(
'wp_ajax_nopriv_' . $method->name,
[self::class, $method->name],
10,
0
);
\add_action(
'wp_ajax_' . $method->name,
[self::class, $method->name],
10,
0
);
}
}
@szepeviktor Thanks a lot for your time! ๐
Based on your last msg I tried this code:
public static function init(): void {
$class_reflection = new ReflectionClass( self::class );
foreach ( $class_reflection->getMethods( ReflectionMethod::IS_PUBLIC ) as $method ) {
if ( ! in_array( $method->name, array_values( self::ACTIONS ), true ) ) {
continue;
}
$action = array_flip( self::ACTIONS )[ $method->name ];
add_action(
'wp_ajax_' . $action,
[ self::class, $method->name ],
10,
0
);
add_action(
'wp_ajax_nopriv_' . $action,
[ self::class, $method->name ],
10,
0
);
}
}
But I get the exact same error...
Moreover it annoys me a bit to use third party code to fix this kind of issue. As code works outside phpstan...
if ( ! in_array( $method->name, array_values( self::ACTIONS ), true ) ) {
๐ก The whole point of using reflections is to go without the ACTIONS
array.
All right. I see you don't want to rename your methods ...
Okay I understand, yes I don't want to rename it.
I'm also seeing this problem on one of my own plugins now. I'm working on a fix but for some reason I can't get the same error to occur during the unit tests. Working on it.