Easily run code asynchronously

Overview

Asynchronous and parallel PHP

Latest Version on Packagist Build Status Quality Score Total Downloads

This library provides a small and easy wrapper around PHP's PCNTL extension. It allows running of different processes in parallel, with an easy-to-use API.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require spatie/async

Usage

use Spatie\Async\Pool;

$pool = Pool::create();

foreach ($things as $thing) {
    $pool->add(function () use ($thing) {
        // Do a thing
    })->then(function ($output) {
        // Handle success
    })->catch(function (Throwable $exception) {
        // Handle exception
    });
}

$pool->wait();

Event listeners

When creating asynchronous processes, you'll get an instance of ParallelProcess returned. You can add the following event hooks on a process.

$pool
    ->add(function () {
        // ...
    })
    ->then(function ($output) {
        // On success, `$output` is returned by the process or callable you passed to the queue.
    })
    ->catch(function ($exception) {
        // When an exception is thrown from within a process, it's caught and passed here.
    })
    ->timeout(function () {
        // A process took too long to finish.
    })
;

Functional API

Instead of using methods on the $pool object, you may also use the async and await helper functions.

use Spatie\Async\Pool;

$pool = Pool::create();

foreach (range(1, 5) as $i) {
    $pool[] = async(function () {
        usleep(random_int(10, 1000));

        return 2;
    })->then(function (int $output) {
        $this->counter += $output;
    });
}

await($pool);

Error handling

If an Exception or Error is thrown from within a child process, it can be caught per process by specifying a callback in the ->catch() method.

$pool
    ->add(function () {
        // ...
    })
    ->catch(function ($exception) {
        // Handle the thrown exception for this child process.
    })
;

If there's no error handler added, the error will be thrown in the parent process when calling await() or $pool->wait().

If the child process would unexpectedly stop without throwing an Throwable, the output written to stderr will be wrapped and thrown as Spatie\Async\ParallelError in the parent process.

Catching exceptions by type

By type hinting the catch functions, you can provide multiple error handlers, each for individual types of errors.

$pool
    ->add(function () {
        throw new MyException('test');
    })
    ->catch(function (MyException $e) {
        // Handle `MyException`
    })
    ->catch(function (OtherException $e) {
        // Handle `OtherException`
    });

Note that as soon as an exception is handled, it won't trigger any other handlers

$pool
    ->add(function () {
        throw new MyException('test');
    })
    ->catch(function (MyException $e) {
        // This one is triggerd when `MyException` is thrown
    })
    ->catch(function (Exception $e) {
        // This one is not triggerd, even though `MyException` extends `Exception`
    });

Stopping a pool

If you need to stop a pool early, because the task it was performing has been completed by one of the child processes, you can use the $pool->stop() method. This will prevent the pool from starting any additional processes.

use Spatie\Async\Pool;

$pool = Pool::create();

// Generate 10k processes generating random numbers
for($i = 0; $i < 10000; $i++) {
    $pool->add(function() use ($i) {
        return rand(0, 100);
    })->then(function($output) use ($pool) {
        // If one of them randomly picks 100, end the pool early.
        if ($output === 100) {
            $pool->stop();
        }
    });
}

$pool->wait();

Note that a pool will be rendered useless after being stopped, and a new pool should be created if needed.

Using another PHP binary

By default the pool will use php to execute its child processes. You can configure another binary like so:

Pool::create()
    ->withBinary('/path/to/php');

Working with tasks

Besides using closures, you can also work with a Task. A Task is useful in situations where you need more setup work in the child process. Because a child process is always bootstrapped from nothing, chances are you'll want to initialise eg. the dependency container before executing the task. The Task class makes this easier to do.

use Spatie\Async\Task;

class MyTask extends Task
{
    public function configure()
    {
        // Setup eg. dependency container, load config,...
    }

    public function run()
    {
        // Do the real work here.
    }
}

// Add the task to the pool
$pool->add(new MyTask());

Simple tasks

If you want to encapsulate the logic of your task, but don't want to create a full blown Task object, you may also pass an invokable object to the Pool.

class InvokableClass
{
    // ...

    public function __invoke()
    {
        // ...
    }
}

$pool->add(new InvokableClass(/* ... */));

Pool configuration

You're free to create as many pools as you want, each pool has its own queue of processes it will handle.

A pool is configurable by the developer:

use Spatie\Async\Pool;

$pool = Pool::create()

// The maximum amount of processes which can run simultaneously.
    ->concurrency(20)

// The maximum amount of time a process may take to finish in seconds
// (decimal places are supported for more granular timeouts).
    ->timeout(15)

// Configure which autoloader sub processes should use.
    ->autoload(__DIR__ . '/../../vendor/autoload.php')
    
// Configure how long the loop should sleep before re-checking the process statuses in microseconds.
    ->sleepTime(50000)
;

Synchronous fallback

If the required extensions (pcntl and posix) are not installed in your current PHP runtime, the Pool will automatically fallback to synchronous execution of tasks.

The Pool class has a static method isSupported you can call to check whether your platform is able to run asynchronous processes.

If you're using a Task to run processes, only the run method of those tasks will be called when running in synchronous mode.

Behind the curtains

When using this package, you're probably wondering what's happening underneath the surface.

We're using the symfony/process component to create and manage child processes in PHP. By creating child processes on the fly, we're able to execute PHP scripts in parallel. This parallelism can improve performance significantly when dealing with multiple synchronous tasks, which don't really need to wait for each other. By giving these tasks a separate process to run on, the underlying operating system can take care of running them in parallel.

There's a caveat when dynamically spawning processes: you need to make sure that there won't be too many processes at once, or the application might crash. The Pool class provided by this package takes care of handling as many processes as you want by scheduling and running them when it's possible.

That's the part that async() or $pool->add() does. Now let's look at what await() or $pool->wait() does.

When multiple processes are spawned, each can have a separate time to completion. One process might eg. have to wait for a HTTP call, while the other has to process large amounts of data. Sometimes you also have points in your code which have to wait until the result of a process is returned.

This is why we have to wait at a certain point in time: for all processes on a pool to finish, so we can be sure it's safe to continue without accidentally killing the child processes which aren't done yet.

Waiting for all processes is done by using a while loop, which will wait until all processes are finished. Determining when a process is finished is done by using a listener on the SIGCHLD signal. This signal is emitted when a child process is finished by the OS kernel. As of PHP 7.1, there's much better support for listening and handling signals, making this approach more performant than eg. using process forks or sockets for communication. You can read more about it here.

When a process is finished, its success event is triggered, which you can hook into with the ->then() function. Likewise, when a process fails or times out, the loop will update that process' status and move on. When all processes are finished, the while loop will see that there's nothing more to wait for, and stop. This is the moment your parent process can continue to execute.

Comparison to other libraries

We've written a blog post containing more information about use cases for this package, as well as making comparisons to other asynchronous PHP libraries like ReactPHP and Amp: http://stitcher.io/blog/asynchronous-php.

Testing

composer test

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Postcardware

You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium.

We publish all received postcards on our company website.

Credits

License

The MIT License (MIT). Please see License File for more information.

Issues
  • Parallel error: Spatie\Async\Output\ParallelError

    Parallel error: Spatie\Async\Output\ParallelError

    Supported 1 Supported1 Supported1 Spatie\Async\Output\ParallelError in /home/el/Php Storm Projects/parallel/vendor/spatie/async/src/Output/ParallelError.php:11 Stack trace: #0 /home/el/Php Storm Projects/parallel/vendor/spatie/async/src/Process/ParallelProcess.php(126): Spatie\Async\Output\ParallelError::fromException('') #1 /home/el/Php Storm Projects/parallel/vendor/spatie/async/src/Process/ProcessCallbacks.php(51): Spatie\Async\Process\ParallelProcess->resolveErrorOutput() #2

    code

    $pool = Pool::create(); $supported = Pool::isSupported(); echo "Supported"." ".$supported." "."
    "; echo "Supported".extension_loaded('posix')."
    "; echo "Supported".extension_loaded('pcntl')."
    ";

    $pool
        ->add(function () {
            // ...
        })
        ->then(function ($output) {
            // On success, `$output` is returned by the process or callable you passed to the queue.
        });
    await($pool);
    

    } catch (Exception $ex) { echo $ex; } return "succeded";

    opened by Elhellawy 14
  • Debugging errors

    Debugging errors

    My code:

            $pool = Pool::create();
    
        	foreach ($xmlNode->childNodes as $item) {
                $pool[] = async(function () use ($item) {
                         //do stuff
                          ...
                         //do more stuff
                         ...
                    }
                })->then(function ($output) {
                    //handle success
                })->catch(function ($ex) {
                    echo PHP_EOL . "something happened, exception. Error: ".$ex->getMessage();
                })->timeout(function () {
                    echo PHP_EOL . "timed out";
                });
        	}
            await($pool);
    

    Output:

    something happened, exception. Error: something happened, exception. Error: something happened, exception. Error: something happened, exception. Error: something happened, exception. Error: something happened, exception. Error: something happened, exception. Error: something happened, exception. Error: something happened, exception. Error: something happened, exception. Error:

    How do I debug the issue? The exception message doesn't seem to be showing. If I just log the exception, instead of the message, I get:

    something happened, exception. Error: Spatie\Async\Output\ParallelError in /home/sayan/Documents/Programming/spatie_test/vendor/spatie/async/src/Output/ParallelError.php:11 Stack trace: #0 /home/sayan/Documents/Programming/spatie_test/vendor/spatie/async/src/Process/ParallelProcess.php(126): Spatie\Async\Output\ParallelError::fromException('') #1 /home/sayan/Documents/Programming/spatie_test/vendor/spatie/async/src/Process/ProcessCallbacks.php(51): Spatie\Async\Process\ParallelProcess->resolveErrorOutput() #2 /home/sayan/Documents/Programming/spatie_test/vendor/spatie/async/src/Pool.php(197): Spatie\Async\Process\ParallelProcess->triggerError() #3 /home/sayan/Documents/Programming/spatie_test/vendor/spatie/async/src/Pool.php(285): Spatie\Async\Pool->markAsFailed(Object(Spatie\Async\Process\ParallelProcess)) #4 /home/sayan/Documents/Programming/spatie_test/vendor/spatie/async/src/Runtime/ParentRuntime.php(70): Spatie\Async\Pool->Spatie\Async{closure}(17, Array) #5 /home/sayan/Documents/Programming/spatie_test/vendor/spatie/async/src/helpers.php(15): Spatie\Async\Runtime\ParentRuntime::createProcess(Object(Closure)) #6 /home/sayan/Documents/Programming/spatie_test/test.php(84): async(Object(Closure)) #7 /home/sayan/Documents/Programming/spatie_test/test.php(50): Test->getListings(Object(DOMElement)) #8 /home/sayan/Documents/Programming/spatie_test/test.php(221): Test->process() #9 {main}

    opened by sayanb 10
  • Add ability to stop a pool early

    Add ability to stop a pool early

    This PR provides the ability to stop a pool early via a $pool->stop() method. This is useful if a child processes completes a task that would make running the remaining processes unnecessary.

    opened by DivineOmega 9
  • Database connection can not be resolved

    Database connection can not be resolved

    I'm testing your package to see if it makes sense for us to use async DB inserts in order to improve performance and I'm running into the following problem when calling $dbModelObject->save() (I should mention that we're using Eloquent and specifically the mongodb extension for it (jenssegers/mongodb) but I'm suspecting that this is generic issue):

    PHP Fatal error:  Uncaught Error: Call to a member function connection() on null
    #0 /var/www/html/BoostFixes/vendor/illuminate/database/Eloquent/Model.php(1205): Illuminate\Database\Eloquent\Model::resolveConnection(NULL)
    #1 /var/www/html/BoostFixes/vendor/jenssegers/mongodb/src/Jenssegers/Mongodb/Eloquent/Model.php(412): Illuminate\Database\Eloquent\Model->getConnection()
    #2 /var/www/html/BoostFixes/vendor/illuminate/database/Eloquent/Model.php(950): Jenssegers\Mongodb\Eloquent\Model->newBaseQueryBuilder()
    #3 /var/www/html/BoostFixes/vendor/illuminate/database/Eloquent/Model.php(628): Illuminate\Database\Eloquent\Model->newModelQuery()
    #4 /var/www/html/BoostFixes/src/Model/BaseModel.php(395): Illuminate\Database\Eloquent\Model->save()
    #5 closure://function() use ($bet) { $bet->save (); }(2): Boost\Model\BaseModel->save()
    #6 /var/www/html/BoostFixes/vendor/spatie/async/src/Runtime/ChildRuntime.php(25): Opis\Closure\SerializableClosure->{closure}()
    #7 {main} in /var/www/html/BoostFixes/vendor/spatie/async/src/Output/Serializab in /var/www/html/BoostFixes/vendor/spatie/async/src/Output/SerializableException.php on line 28
    

    Just to be clear, the code works fine without using your package; it seems to be that somehow the DB context is not available in the child/async process. Could you please advise how/if it is possible to get this to work?

    opened by innobrig 9
  • Use fitting version of PHPUnit in CI

    Use fitting version of PHPUnit in CI

    https://phpunit.de/supported-versions.html

    opened by szepeviktor 8
  • Bugfix handling exception in synchronous process

    Bugfix handling exception in synchronous process

    Add an abstract method resolveErrorOutput to ProcessCallbacks trait currently only ParallelProcess implement it.

    opened by vuongxuongminh 8
  • Serialization of xy is not allowed while passing objects as callback values to use

    Serialization of xy is not allowed while passing objects as callback values to use

    Thank for this library. I'm eager to try out and see the speedup on @Rector, just came across one issue while running this code:

    $i = 0;
    
    $pool = Pool::create();
    
    /** @var SplFileInfo $fileInfo */
    foreach ($fileInfos as $fileInfo) {
        $pool->add(function () use ($fileInfo, $i) {  // <--------------- here is the issue
            // long-durring process
            $this->processFile($fileInfo, $i);
        })->then(function () {
            // success
            $this->consoleStyle->progressAdvance();
        })->catch(function (Throwable $throwable) use ($fileInfo) {
            // fail
            $this->consoleStyle->newLine();
            throw new FileProcessingException(
                sprintf('Processing of "%s" file failed.', $fileInfo->getPathname()),
                $throwable->getCode(),
                $throwable
            );
        });
    }
    
    $pool->wait();
    

    I get this exception:

    In SerializableClosure.php line 156:
                                                                              
      [Exception]                                                             
      Serialization of 'Symfony\Component\Finder\SplFileInfo' is not allowed 
    

    It's realated probably to object SplFileInfo serialization, which is one of arguments, by Opis\Closure\SerializableClosure. It's called in $pool->add()

    Do you have any suggesstion how to solve this?

    I cannot pass string, becase I work with the object further in the method.

    opened by TomasVotruba 8
  • Fatal error:  Uncaught Spatie\Async\Output\ParallelError

    Fatal error: Uncaught Spatie\Async\Output\ParallelError

    Hello. I'm trying to run my code asynchronously, but I'm recieving an unknown error. Could you please take a look into it?

    My environment: ubuntu 16.04, PHP 7.2.7 with PHP-FPM.

    My code:

    $pool = Pool::create();
    
    $pool->add(function() {
        error_log('Async snapshot called');
        $html = getSnapshotHTML($full_uri);
        $source_code = pg_escape_string($html['source_code']);
        $url_path = parse_url($full_uri, PHP_URL_PATH);
    
        if($html['status_code'] == 200) {
            $query = "UPDATE snapshots SET (html, inserted) = ('$source_code', '$now') WHERE pathname = '{$url_path}'";
            $result = pg_query($query) or die('Query failed: ' . pg_last_error());   
        }
    });
    

    Stack trace:

    2018/07/03 21:53:07 [error] 22566#22566: *2 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught Spatie\Async\Output\ParallelError in /var/www/production/engine/vendor/spatie/async/src/Output/ParallelError.php:11
    Stack trace:
    #0 /var/www/production/engine/vendor/spatie/async/src/Process/ParallelProcess.php(126): Spatie\Async\Output\ParallelError::fromException('')
    #1 /var/www/production/engine/vendor/spatie/async/src/Process/ProcessCallbacks.php(51): Spatie\Async\Process\ParallelProcess->resolveErrorOutput()
    #2 /var/www/production/engine/vendor/spatie/async/src/Pool.php(197): Spatie\Async\Process\ParallelProcess->triggerError()
    #3 /var/www/production/engine/vendor/spatie/async/src/Pool.php(285): Spatie\Async\Pool->markAsFailed(Object(Spatie\Async\Process\ParallelProcess))
    #4 /var/www/production/engine/vendor/symfony/process/Process.php(830): Spatie\Async\Pool->Spatie\Async\{closure}(17, Array)
    #5 /var/www/production/engine/vendor/symfony/process/Process.php(168): Symfony\Component\Process\Process->stop(0)
    #6 [internal function]: Symfony\Component\Process\Proces" while reading upstream
    
    opened by abriginets 8
  • Simple example not working

    Simple example not working

    [2018-11-30 16:47:58] local.DEBUG: The serialized closure is signed. Make sure you use a security provider for both serialization and unserialization.

    #0 [internal function]: Opis\Closure\SerializableClosure->unserialize('@{"closure":"a:...') #1 /home/vagrant/code/vendor/opis/closure/functions.php(34): unserialize('C:32:"Opis\Clos...') #2 /home/vagrant/code/vendor/spatie/async/src/Runtime/ParentRuntime.php(92): Opis\Closure\unserialize('C:32:"Opis\Clos...') #3 /home/vagrant/code/vendor/spatie/async/src/Runtime/ChildRuntime.php(23): Spatie\Async\Runtime\ParentRuntime::decodeTask('QzozMjoiT3Bpc1x...') #4 {main}

        $pool = \Spatie\Async\Pool::create();
    
        $json = '';
    
    
    
        $pool->add(function() {
    
            logger('rates test 1');
    
            return '{"id":"1","label":"test 1","cost":100}';
    
        })->then(function($out) use(&$json) {
    
            logger('rates test 2');
    
            if( $json ) $json .= ',';
    
            $json .= $out;
    
        })->catch(function(Throwable $e) {
    
            logger($e->getMessage());
    
        });
    
    
        $pool->add(function() {
    
            return '{"id":"2","label":"test 2","cost":200}';
    
        })->then(function($out) use(&$json) {
    
            if( $json ) $json .= ',';
    
            $json .= $out;
    
        })->catch(function(Throwable $e) {
    
            //
    
        });
    
    
        $pool->add(function() {
    
            return '{"id":"3","label":"test 3","cost":300}';
    
        })->then(function($out) use(&$json) {
    
            if( $json ) $json .= ',';
    
            $json .= $out;
    
        })->catch(function(Throwable $e) {
    
            //
    
        });
    
    
        $pool->wait();
    
        logger('rates test 3');
    
        echo '{"rates":[' . $json . ']}';
    

    The $json variable is blank

    opened by shrimpwagon 7
  • How to check my parent and child process executed in parrallel??

    How to check my parent and child process executed in parrallel??

    use Spatie\Async\Pool; public function save(){ //my parent function goes //my child process starts $pool[] = async(function () use($data) { sleep(3); })->then(function ($output) { })->catch(function ($exception) { }); await($pool); sleep(3); } To check I included sleep(3) in both parent and child process and it takes 6 seconds but i think this was not correct because if it was executed in parallel means it has to take only 3 seconds. Please guide me for this issue.

    opened by developeronboard 7
  • Why is it slow ?

    Why is it slow ?

    Hello everyone ! This package look awesome, but I got few problems with it, especially with the speed of parallelism! Here is my test , with Laravel 8.7

    $start = now();
    $number = 100;
    echo 'Start of script <br><br>';
    foreach (range(1,$number) as $i){
        echo $i;
    }
    echo '<br> Time without parallelism : ' . now()->diffInMicroseconds($start) . ' microseconds <br>';
    
    $start = now();
    $pool = Pool::create();
    foreach (range(1, $number) as $i) {
        $pool->add(function () use ($i) {
            return $i;
        })->then(function (int $output) {
            echo $output;
        });
    }
    $pool->wait();
    echo '<br> Time with parallelism : ' . now()->diffInMicroseconds($start) . ' microseconds';
    

    And here is the result :

    Start of script
    
    12345678910111213 ....
    Time without parallelism : 16 microseconds
    42137961551112810 ...
    Time with parallelism : 707905 microseconds
    

    So the code without parallelism is 44187 faster than with parallelism. And it's only with a loop of 100 iteration. Did I make a mistake ?

    Thanks for you help.

    opened by Vicftz 0
  • Add a results(): Generator method.

    Add a results(): Generator method.

    Hi!

    This PR propose the addition of the results() method that returns a generator with results. This function has the same logic as in wait() but return results using yield. The wait() method just return the array from the generator (Making sure the behavior is the same and no extra tests are needed).

    With this 3 methods have been added:

    public function shiftResult()
    public function hasResults(): bool
    public function tick(): bool
    

    Those functions are used by the generator, they provide clear intend and are necessary to implement more complex generators from userland (without extending Pool::class).

    Update:

    3 more methods are added to prune list that grow for ever (ie memory leak on long processes):

    public function pruneFinished()
    public function pruneFailed()
    public function pruneTimeouts()
    

    Thanks and happy new year :-)

    opened by vdauchy 0
  • Is this repo alive

    Is this repo alive

    I've posted 3 pull requests a month ago, nobody cared enough to review it.

    Sounds weird from spati with a package with 2k stars.

    What's going on?

    opened by Stevemoretz 0
  • Exception: Serialization of 'PDO' is not allowed

    Exception: Serialization of 'PDO' is not allowed

    Hello. i'm trying to use this package to make a parallel processing on some methods I have and I got this error Exception: Serialization of 'PDO' is not allowed in file /var/www/html/vendor/opis/closure/src/SerializableClosure.php on line 155

       $pool = Pool::create();
    
    
        foreach ($this->transportadoras as $transportadora) {
    
    
            $pool->add(function () use ($transportadora) {
    
                return $client->post("https://reqbin.com/echo/post/json", $this->request->all())->json();
    
            })->then(function ($response) {
                if (array_key_exists('data', $response)) {
                    $this->payload['response'][] = $response;
                } else {
                    $this->payload['response'] = array_merge($response, $this->payload['response']);
                }
            });
        }
    
        dd($pool->wait());
    
    opened by lucassmacedo 0
  • Support of PHP versions?

    Support of PHP versions?

    I see this library still supports PHP 7.1, which is End of Life (EOL) for a long time. Even 7.3 is EOL as of today.

    What's the policy about PHP support? The only supported versions are 7.4, 8.0 and 8.1

    In my opinion libraries should drop support of PHP versions that are end of life, because it makes contributing to this library much easier.

    opened by stephanvierkant 3
  • Question about pthreads

    Question about pthreads

    I just finished writing some advanced code based on this library which let's me open a process and keep it running so it makes sense to be used with websockets and larval, thanks for making this possible for me.

    But then I searched if threads exist in php and found this https://stackoverflow.com/a/15501449/10268067

    So what is the advantages and disadvantages of this method compared to pthreads?

    opened by Stevemoretz 0
  • Make functionality more expandable

    Make functionality more expandable

    Right now, you can only use one autoloader (using public function autoload(string $autoloader): self), however you can use different binaries using withBinary method, so I a couple of extra features overriding the static properties if needed the methods are :

    1. withAutoloader
    2. withChildProcessScript

    1. withAutoloader

    This basically provides the possibility of a different autoloader for every pool.

        public function withAutoloader(string $autoloader): self
        {
            $this->autoloader = $autoloader;
    
            return $this;
        }
    

    it simply overrides the static autoloader if used, it is not a replacement, that's why you don't see the @deprecated sign on the old autoload method, that method is still relevant specially when using the functional api, but this new method can be used for other cases.

    2. withChildProcessScript

    Currently there is no way to add some extra logic to the ChildRuntime.php but with this new method, you can write a completely custom script, and do whatever you want with it.

        public function withChildProcessScript(string $childProcessScript, array $extraArgs = []): self
        {
            $this->childProcessScript = $childProcessScript;
            $this->extraChildProcessArgs = $extraArgs;
    
            return $this;
        }
    

    the extraArgs will be assigned to the custom child script, giving it $argv[6,7,...].

    I have read into the library, and all these changes are compatible and exactly in the same way the rest of the library is written, hope you'd like this PR. Let me what you know.

    with Regards Steve Moretz

    opened by Stevemoretz 0
  • change to Serializable Closure of laravel

    change to Serializable Closure of laravel

    As mentioned in https://github.com/laravel/serializable-closure

    This project is a fork of the excellent opis/closure: 3.x package. At Laravel, we decided to fork this package as the upcoming version 4.x is a complete rewrite on top of the FFI extension. As Laravel is a web framework, and FFI is not enabled by default in web requests, this fork allows us to keep using the 3.x series while adding support for new PHP versions.

    the version 4 will stop working, so it's better use this package which is maintained by laravel.

    opened by Stevemoretz 0
  • Add Ability to run in a custom loop

    Add Ability to run in a custom loop

    My use case was, using ratchet-php which inside of it uses react-php, which has a loop calling $pool->wait() was basically blocking the loop, I noticed inside the wait function there was a sleep method for retrying, so all I needed was to be able to just use react-php's timer, so the loop won't be blocked, for that I also need the sleep time, so I added a simple function to get that as well, here's the implementation:

        private function handleWait(Pool $pool) {
            Loop::get()->addTimer($pool->getSleepTime() / 1000, function () use (
                $pool
            ) {
                $pool->baseWait();
                $this->handleWait($pool);
            });
        }
    

    and the result was obviously the same as before, only this time non blocking. This can come in handy in many cases.

    the main issue leading me to fix this was : https://github.com/spatie/async/issues/170

    opened by Stevemoretz 0
  • Permission denied

    Permission denied

    I am running Ubuntu 20.04 with Apache with php 8.0 and getting a permissions denied error.

    opened by starprog 0
Releases(1.5.3)
Owner
Spatie
We create open source, digital products and courses for the developer community
Spatie
Run your WP site on github pages, php innovation award winner https://www.phpclasses.org/package/12091-PHP-Make-a-WordPress-site-run-on-GitHub-pages.html

Gitpress Run wordpress directly on github pages Gitpress won the innovation award for may 2021 Read more about this https://naveen17797.github.io/gitp

naveen 9 Oct 9, 2021
Preload your sweet sweet code to opcache with a composer command, making your code faster to run.

Composer Preload Preload your sweet sweet code to opcache with a composer command, making your code run faster. Composer Preload is a composer plugin

Ayesh Karunaratne 190 Jan 11, 2022
A small library to help run PHP servers easily and quickly.

PHP Server A small library to help run PHP servers easily and quickly. Installation composer require ahmard/php-server Usage PHP Built-In Server An i

Ahmad Mustapha 8 Nov 19, 2021
Easily create and work with code snippets from PHP

code-snippets Easily create and work with code snippets from source code files of any type in PHP. The original code this package is based on was borr

Permafrost Software 7 Sep 30, 2021
Fly50W is a new language which helps you build simple apps using more than 500k lines of code easily.

Fly50W is a new language which helps you build simple apps using more than 500k lines of code easily. Installation

null 4 Nov 7, 2021
Easily add logs anywhere in your Magento 2 code

Magento 2 Simple Log Easily add logs anywhere in the code (like Magento 1). Requirements Requires Magento 2 in any version. Installation Add the Log.p

Matthieu Vion 19 Dec 27, 2021
λ Run PHP Coroutines & Fibers as-a-Service on the AWS Lambda.

λ Swoole Runtime for AWS Lambda Run PHP Coroutines & Fibers as-a-Service on the AWS Lambda. Getting started Create your Lambda function index.php <?ph

Leo Cavalcante 27 Dec 13, 2021
Run Telegram PHP Bot on Windows Localhost without Host or VPN.

Run Telegram PHP Bot on Windows Localhost without Host or VPN.

iNeoTeam | آی نئو 2 Oct 3, 2021
Run the following commands in your terminal to setup the project

Run the following commands in your terminal to setup the project You must have the LAMP installed on your system git clone https://github.com/Bashar-A

null 1 Nov 6, 2021
Run PHP scripts on the fly at runtime on a PocketMine-MP server (useful for debugging)

Scripter Run PHP scripts on the fly at runtime on a PocketMine-MP server. This is useful for runtime debugging, when you don't want to restart the ser

Dylan's PocketMine-MP Plugins 12 Dec 3, 2021
Learn how to run WordPress with Docker. Read about our experiences and start off with an easy boilerplate.

Hi! We're Dan and Jay. We're a two person team with a passion for open source products. We created Server Side Up to help share what we learn. Find us

Server Side Up 3 Jan 9, 2022
Simple, modern looking server status page with administration and some nice features, that can run even on shared webhosting

Simple, modern looking server status page with administration and some nice features, that can run even on shared webhosting

Server status project 325 Jan 13, 2022
Like Cloud Drive Run on Raspbian + Nginx + PHP

Raspberry-Pi-Cloud Like Cloud Drive Run on Raspbian + Nginx + PHP I Made a Project Called Raspberry-Pi-Cloud. it's on testing stage help me to test it

null 1 Dec 25, 2021
This project processes a small database with php all on a web server. This project uses XAMPP to run the web server and the database.

PHP-introduction This project processes a small database with php all on a web server. This project uses XAMPP to run the web server and the database.

Tyler Jacques 1 Jan 6, 2022
Result of our code-along meetup writing PHP 8.1 code

PHP 8.1 Demo Code This code demonstrates various PHP 8.0 and 8.1 features in a realistic, functional (but incomplete) codebase. The code is part of so

azPHP 2 Nov 14, 2021
⚗️ Adds code analysis to Laravel improving developer productivity and code quality.

⚗️ About Larastan Larastan was created by Can Vural and Nuno Maduro, got artwork designed by @Caneco, is maintained by Can Vural, Nuno Maduro, and Vik

Nuno Maduro 3.6k Jan 18, 2022
Free ZIP Code API - Free Access to Worldwide Postal Code Data

About Zipcodebase - Free Zip Code API Zipcodebase is a zip code API that was founded in 2019 to solve common issues with postal code data. As we have

SaaS Industries 3 Nov 17, 2021
Dead Code Detector (DCD) for PHP code.

This project is no longer maintained and its repository is only kept for archival purposes. PHP Dead Code Detector (PHPDCD) phpdcd is a Dead Code Dete

Sebastian Bergmann 405 Jan 18, 2022
:date: The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects

sabre/vobject The VObject library allows you to easily parse and manipulate iCalendar and vCard objects using PHP. The goal of the VObject library is

sabre.io 508 Jan 11, 2022