krakjoe / pthreads

Threading for PHP - Share Nothing, Do Everything :)
Other
3.47k stars 503 forks source link

Serialization of 'Closure' is not allowed in Worker #942

Open landall opened 5 years ago

landall commented 5 years ago

Environment

PHP 7.2.19 (cli) (built: May 29 2019 14:17:01) ( ZTS MSVC15 (Visual C++ 2017) x86 ) Pthread 3.2.0 Win10 x64

Summary

When I assign a object with a member of GuzzleHttp\Client to a field of my worker class, I raise an exception saying Serialization of 'Closure' is not allowed.

Reproducing Code

class TaskQueueWorker extends \Worker { public function __construct($client) { $this->client = $client; }

public static $client;

}

$client is an object of a class with a sub object of GuzzleHttp\Client.

Its package information: "name": "guzzlehttp/guzzle", "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", "shasum": "" }, "require": { "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.4", "php": ">=5.5" },

Expected Output

Actual Output

raise a fatal error.

landall commented 5 years ago

also happened in CentOS 7 with remi-php7.2 rpm packages. PHP 7.2.19 (cli) (built: May 29 2019 11:10:45) ( ZTS )

Installed Packages php.x86_64 7.2.19-2.el7.remi @remi-php72 php-cli.x86_64 7.2.19-2.el7.remi @remi-php72 php-common.x86_64 7.2.19-2.el7.remi @remi-php72 php-json.x86_64 7.2.19-2.el7.remi @remi-php72 php-pecl-pthreads.x86_64 3.2.0-1.el7.remi.7.2 @remi-php72

AlexSayHello commented 5 years ago

The properties of the instances that inherit from Threaded are serialized so that the information they host can be passed between contexts.

When you pass your http client to your worker, the engine tries to serialize the instance of GuzzleHttp\Client and at some point you will find an anonymous function or closure. Anonymous functions cannot be serialized due to their nature. It's like trying to do:

$result = serialize(function () {});

That will throw a fatal error: Serialization of 'Closure' is not allowed

If you want to create an instance that is shared by all the threads of your worker you can do the following.

<?php

use Worker;

class TaskQueueWorker extends Worker
{
    protected static $client;

    public function run()
    {
        // It is necessary to call the autoload composer file, since the context
        // of the worker is new and does not have the spl autoload function
        // for psr-4
        require 'vendor/autoload.php';
    }

    public function getClient()
    {
        if (self::$client) {
            return self::$client;
        }

        self::$client = new GuzzleHttp\Client();

        return self::$client;
    }
}

You can learn more about how to share objects in the examples: https://github.com/krakjoe/pthreads/blob/master/examples/MySQLi.php

dktapps commented 5 years ago

@AlexSayHello That isn't sharing. Statics are thread-local, not shared.

AlexSayHello commented 5 years ago

@dktapps When I refer to "shared" I mean that the instance is available from the thread through $this->worker->getClient(). Maybe I have not used the most appropriate concept to describe it. I wasn't referring to sharing data.

landall commented 5 years ago

Does this means I must create the instance as a thread-local object if it uses an anonymous function or closure? I cannot control the code from others' package.