laracoft's avatar

ErrorException from exec()

Hi,

Invalid argument supplied for foreach()
 
in ArgvInput.php line 246 
at HandleExceptions->handleError(2, 'Invalid argument supplied for foreach()', '/project/vendor/symfony/console/Input/ArgvInput.php', 246, array('isOption' => false))
in ArgvInput.php line 246 
at ArgvInput->getFirstArgument()
in Application.php line 1049 
at Application->getCommandName(object(ArgvInput))
in Application.php line 81 
at Application->run(object(ArgvInput), object(ConsoleOutput))
in Kernel.php line 133 
at Kernel->handle(object(ArgvInput), object(ConsoleOutput))
in artisan line 36 
try {
    exec("php artisan test");
} catch (\Exception $e) {
}

I was getting this exception on a shared hosting. Eventually, I tracked it down to this line exec("php artisan test"). Next, I placed a try-catch around the exec() but it is unable to catch the exception.

  1. Why is the try-catch unable to catch the exception?
  2. Why does a PHP function exec() end up in Laravel's exception handling rather than my try-catch?

I'm aware that changing my code to php -d register_argc_argv=On artisan test solves the issue, but my focus is why does a bad exec() throws such a indecipherable exception?

Thank you.

0 likes
5 replies
Snapey's avatar

its a bit convoluted, but you will only capture the exception if it occurs in the same thread as the exec command,

If it occurs in the artisan command (which is in a different exec session) then the error will need to be handled there.

Why not call the Artisan class and not via exec?

laracoft's avatar

Sorry, I should have been clearer. It became test as I was experimenting with the code.

test is actually a long running daemon queue:worker --tries=3 and after starting it, my code needs to retrieve the PID to check that it is indeed running, otherwise throw an exception/notification.

Furthermore, as it is a shared hosting, there is a cronjob to ensure this PID is still running every X minutes.

The above is basically my explanation on why I was working with exec(). I wasn't able to get the same thing done with Symfony\Component\Process\Process.

But I'm still very curious about the way exec() works, let me try and digest your comments first. I also found that the exception is actually thrown by ArgvInput not checking for NULLs before a foreach. That ought to be fixed so that it does not create such confusing exceptions.

laracoft's avatar
try {
    exec("invalid_executeable");
} catch (\Exception $e) {
    echo "this will never execute";
}	

@snapey do you mean that the above will not throw an exception/error?

Snapey's avatar

Im saying that when you exec php artisan you are booting a new instance of Laravel. Any errors that occur in that instance can only be caught in that instance - not in the caller.

I dont know if it helps, but I worked around lack of supervisor recently by running the queue worker with the option to terminate when empty. I then fired this every five minutes, knowing that my queues would empty in that time and then the worker would be restarted again.

laracoft's avatar

Ok, I have broken this into 3 issues with #3 being the main focus of the opening question:

  1. Bug in ArgvInput.php causing unnecessary exception - fixed
  2. How to get queue:worker running on shared hosting - fixed
  3. exec("invalid_executable") will throw an exception, why is it caught by Laravel's exception handler instead of my try-catch?

Please or to participate in this conversation.