Skip to content
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

Internal error: Internal error: Multiple variants - use selectFromArgs() instead. #133

Closed
arnaudpfu opened this issue Nov 17, 2022 · 13 comments · Fixed by #135
Closed

Internal error: Internal error: Multiple variants - use selectFromArgs() instead. #133

arnaudpfu opened this issue Nov 17, 2022 · 13 comments · Fixed by #135

Comments

@arnaudpfu
Copy link

arnaudpfu commented Nov 17, 2022

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.

@szepeviktor
Copy link
Owner

Hello Arnaud! 👋🏻

I hope @johnbillion will reveal the cause of your error.

BTW The second version is more readable!

@szepeviktor
Copy link
Owner

szepeviktor commented Nov 17, 2022

After looking at your intention I recommend my 3+1 hooking thingies :)
https://github.com/szepeviktor/Toolkit4WP/tree/master/src

@johnbillion
Copy link
Sponsor Contributor

Thanks for the report, I'll take a look.

@arnaudpfu
Copy link
Author

Sorry @szepeviktor but I haven't found why your repo could help me. 😅

@szepeviktor
Copy link
Owner

szepeviktor commented Nov 17, 2022

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.

@arnaudpfu
Copy link
Author

@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.

@szepeviktor
Copy link
Owner

szepeviktor commented Nov 17, 2022

@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

@szepeviktor
Copy link
Owner

szepeviktor commented Nov 17, 2022

@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
            );
        }
    }

@arnaudpfu
Copy link
Author

@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...

@szepeviktor
Copy link
Owner

if ( ! in_array( $method->name, array_values( self::ACTIONS ), true ) ) {

💡 The whole point of using reflections is to go without the ACTIONS array.

@szepeviktor
Copy link
Owner

All right. I see you don't want to rename your methods ...

@arnaudpfu
Copy link
Author

Okay I understand, yes I don't want to rename it.

@johnbillion
Copy link
Sponsor Contributor

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.

szepeviktor pushed a commit that referenced this issue Dec 1, 2022
* Add a failing test for #133.

* Avoid a PHPStan exception when a callback has multiple variants.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants