Opis Closure - a library that aims to overcome PHP's limitations regarding closure serialization

Overview

Opis Closure

Tests Latest Stable Version Latest Unstable Version License

Serializable closures

Opis Closure is a library that aims to overcome PHP's limitations regarding closure serialization by providing a wrapper that will make all closures serializable.

The library's key features:

  • Serialize any closure
  • Serialize arbitrary objects
  • Doesn't use eval for closure serialization or unserialization
  • Works with any PHP version that has support for closures
  • Supports PHP 7 syntax
  • Handles all variables referenced/imported in use() and automatically wraps all referenced/imported closures for proper serialization
  • Handles recursive closures
  • Handles magic constants like __FILE__, __DIR__, __LINE__, __NAMESPACE__, __CLASS__, __TRAIT__, __METHOD__ and __FUNCTION__.
  • Automatically resolves all class names, function names and constant names used inside the closure
  • Track closure's residing source by using the #trackme directive
  • Simple and very fast parser
  • Any error or exception, that might occur when executing an unserialized closure, can be caught and treated properly
  • You can serialize/unserialize any closure unlimited times, even those previously unserialized (this is possible because eval() is not used for unserialization)
  • Handles static closures
  • Supports cryptographically signed closures
  • Provides a reflector that can give you information about the serialized closure
  • Provides an analyzer for SuperClosure library
  • Automatically detects when the scope and/or the bound object of a closure needs to be serialized in order for the closure to work after deserialization

Documentation

The full documentation for this library can be found here.

License

Opis Closure is licensed under the MIT License (MIT).

Requirements

  • PHP ^5.4 || ^7.0 || ^8.0

Installation

Opis Closure is available on Packagist and it can be installed from a command line interface by using Composer.

composer require opis/closure

Or you could directly reference it into your composer.json file as a dependency

{
    "require": {
        "opis/closure": "^3.5"
    }
}

Migrating from 2.x

If your project needs to support PHP 5.3 you can continue using the 2.x version of Opis Closure. Otherwise, assuming you are not using one of the removed/refactored classes or features(see CHANGELOG), migrating to version 3.x is simply a matter of updating your composer.json file.

Semantic versioning

Opis Closure follows semantic versioning specifications.

Arbitrary object serialization

We've added this feature in order to be able to support the serialization of a closure's bound object. The implementation is far from being perfect, and it's really hard to make it work flawless. We will try to improve this, but we can't guarantee anything. So our advice regarding the Opis\Closure\serialize|unserialize functions is to use them with caution.

Comments
  • InvalidArgumentException : Unknown setter 'date'

    InvalidArgumentException : Unknown setter 'date'

    Hello,

    I have an issue with Carbon dates that are serialized through GitHub - opis/closure: Serialize closures (anonymous functions)

    Laravel version: 6.11.0 Carbon version: 2.28.0 PHP version: 7.3.10 Opis/Closure version: 3.5.1

    The problem seems to occur after upgrading to Laravel 6 and therefor upgraded from Carbon 1 to Carbon 2.

    I wasn’t sure if this belongs to the Carbon or Opis issues. So I’ve posted this question on both. (InvalidArgumentException : Unknown setter ‘date’ · Issue #1988 · briannesbitt/Carbon · GitHub)

    When a closure is serialized:

    return serialize(new SerializableClosure($closure, true));
    

    I get this error: InvalidArgumentException : Unknown setter 'date’.

    This boils down to /nesbot/carbon/src/Carbon/Traits/Date.php:1166.

    I’ve googled this issue for some time now and I believe it has got a lot to do with the depreciation of serializeUsing. As found in issue Provide an alternative to serializeUsing to Laravel users · Issue #1870 · briannesbitt/Carbon · GitHub. @driesvints

    However after reading multiple threads I’m not able to find a solution. I really hope someone can help me steering me to the right direction 🙏.

    Thanks!

    opened by stefro 32
  • When the file does not exist, do not process tokens, when there is no tokens do not count null.

    When the file does not exist, do not process tokens, when there is no tokens do not count null.

    Use case: code is comming from the database, not a file. for a bit of background please see views_php issue: https://www.drupal.org/project/views_php/issues/2274543

    I will sum it up:

    The php code is comming from the database, not a file, closure library was prior to this commit trying to do a file_get_contents on this string: "path/to/drupal/and/module/path/views_php.module eval()'d code" of course there is no filename called eval()'d code.

    This ONLY occurs when using views_bulk_operations on views with a field containing views_php enabled code , I'm not sure why. Normal use cases for views_php seem ok and do not try to load a file that doesn't exist.

    opened by joejoseph00 30
  • Fix issue where the code is NOT comming from a file, the code is comm…

    Fix issue where the code is NOT comming from a file, the code is comm…

    …ing from the database.

    In this use case, php 7.3.x with drupal 7 and the views_php module when using views_bulk_operations.

    The php code is comming from the database, not a file, closure library was prior to this commit trying to do a file_get_contents on this string: "path/to/drupal/and/module/path/views_php.module eval()'d code" of course there is no filename called eval()'d code.

    Therefore, this patch is what I cooked up. see explanation description of this error here: https://www.drupal.org/comment/13138161#comment-13138161

    This commit appears to have resolved these issues. (knock on wood, I am still reviewing).

    opened by joejoseph00 17
  • Serialization of 'Closure' is not allowed

    Serialization of 'Closure' is not allowed

    Hi, first thank you for this awesome library!

    I've a problem serializing this context:

    class Foo
    {
        private $options;
    
        public function __construct()
        {
            $this->options['is_valid'] = function () {
                return true;
            };
        }
    }
    
    $foo = new Foo();
    
    $serializable = new SerializableClosure(function () use ($foo) {
        // do something.
    });
    
    serialize($serializable);
    

    It throws the exception because use objects are not mapped in mapByReference() (unless being \stdClass), it can happen into $this context too. Any suggestion?

    opened by yceruto 12
  • Unbinding $this of closure is deprecated on php 7.4

    Unbinding $this of closure is deprecated on php 7.4

    ErrorException {#1613 #message: "Unbinding $this of closure is deprecated" #code: 0 #file: "./vendor/opis/closure/src/SerializableClosure.php" #line: 263 #severity: E_DEPRECATED trace: { ./vendor/opis/closure/src/SerializableClosure.php:263 { …} Illuminate\Foundation\Bootstrap\HandleExceptions->handleError() {} ./vendor/opis/closure/src/SerializableClosure.php:263 { …} Opis\Closure\SerializableClosure->unserialize() {}

    opened by envatic 11
  • isScopeRequired() false positive

    isScopeRequired() false positive

    Test case:

    function () {
        static $i = 0;
        return $i;
    }
    

    This static is for variable and doesn't reference the scope class.

    It looks like this case should be removed: https://github.com/opis/closure/blob/c37b40d59d9afffc2e5e958e2e5ccdb08634f81d/src/ReflectionClosure.php#L361-L364

    opened by b1rdex 11
  • Namespace

    Namespace

    Hi, let me introduce an issue regarding namespaces.

    My closure is kind of :

    function () { $class = 'Full\Name\Space'; new $class(); }

    But it is my closure in declared in namespace SomeOther

    So when it is serialized => closure becomes that :

    function () { $class = 'Full\Name\Space'; new \SomeOther$class(); }

    And, guess what happend on execute => Yeah, a nice parse error.

    Is there a kind of params to set for SerializableClosure do not attempt to fully qualified new object();

    opened by MockingMagician 11
  • PHP 8 support

    PHP 8 support

    We've started looking into PHP 8 builds for laravel/framework. We'll need a release of opis/closure or a nightly build for a next major version that allows for PHP 8 in its requirements. Nothing urgent but would be cool to set up soon.

    opened by driesvints 10
  • uncatchable error trying to unserialize

    uncatchable error trying to unserialize

    I have the following code:

      $model = new MyModel();
      $sm = Opis\Closure\serialize($model);
      try {
        $usm = Opis\Closure\unserialize($sm);
      } catch (\Exception $e) {
        $usm = $e->getMessage();
      }
    

    The $model gets serialized properly, but I get a 500 error when calling unserialize. Any idea?

    opened by mjauvin 9
  • Error: Cannot write property

    Error: Cannot write property

    I have a class that extends mysqli class and those properties are defined as public but are actually read only properties so I have to put $property->setValue() and $property->getValue() inside a try and catch block for it to work.

    Example:

    do{
        foreach ($reflection->getProperties() as $property){
            if($property->isStatic()){
                continue;
            }
            $property->setAccessible(true);
            $value = $property->getValue($instance);
            if(is_array($value) || is_object($value)){
                $this->mapByReference($value);
            }
    
            try {
                $property->setValue($data, $value);
            }
            catch(\Exception $e) {}
            catch(\Throwable $e) {}
        }
    } while($reflection = $reflection->getParentClass());
    

    and

    do{
        if(!$reflection->isUserDefined()){
            break;
        }
        foreach ($reflection->getProperties() as $property){
            if($property->isStatic()){
                continue;
            }
            $property->setAccessible(true);
    
            try {
                $item = $property->getValue($data);
            } catch(\Exception $e) {
                continue;
            } catch(\Throwable $e) {
                continue;
            }
    
            if ($item instanceof SerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) {
                $this->code['objects'][] = array(
                    'instance' => $data,
                    'property' => $property,
                    'object' => $item instanceof SelfReference ? $this : $item,
                );
            } elseif (is_array($item) || is_object($item)) {
                $this->mapPointers($item);
                $property->setValue($data, $item);
            }
        }
    } while($reflection = $reflection->getParentClass());
    
    opened by RV7PR 9
  • Test package with next PHP version 8.1

    Test package with next PHP version 8.1

    PHP 8.1 will deprecate Serializable those would be good to be fixed in advance.

    Here is the error I get when trying to run with dev-master version of PHP:

    In SerializableClosure.php line 18:
    
    The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary)
    

    Those method get the raw array instead of string so I need to investigate a bit more to propose a fix.

    But first I suggest to add PHP 8.1 to the CI so new BC can be caught sooner.

    opened by kylekatarnls 8
  • Opis\Closure enters an unusable state if used in try/catch

    Opis\Closure enters an unusable state if used in try/catch

    I have the following use case:

    • $foo may contain data that is either serialized or unserialized.
    • If it is serialized, I need to unserialize to ensure $foo is now in a consistent, unserialized state.

    Best I can tell there is no official way to detect if something can be unserialized. So the way I had implemented was in a seemingly-innocent try/catch block:

    $bar = $foo;
    try {
        $bar = \Opis\Closure\unserialize($foo);
    } catch (Exception $e) {}
    

    Now $bar is always unserialized.

    However this now causes \Opis\Closure to enter essentially a broken state if the try block fails. As soon as that occurs, the locks depth used in \Opis\Closure\SerializableContext::enterContext will now never reach zero, causing all future serializations to happen in the same context. There is no way to forcibly reset the context state either.

    This creates some extremely random bugs - in my situation certain tests late in the test suite fail because when attempting to serialize an object instance using \Opis\Closure\serialize, \Opis\Closure\SerializableClosure::wrapClosures updates the instance by reference to become simply boolean true. This happens because we are attempting to serialize inside the context of a previous serialization ... but only if specific other tests earlier in the suite were run first. The tests are bleeding into each other due to \Opis\Closure's essentially global state.

    In a wider use case, its not unforeseeable that someone would try unserializing in a much wider try/catch block than my example above. If it falls over and their code execution continues, it is going to produce some very bizarre & hard-to-track-down bugs.

    So best I can tell I'm stuck with the current implementation. For now I've just created a class that extends \Opis\Closure\SerializableClosure and provides a clean method:

    /**
     * Restore Opis\Closure to a clean state, read for the next call to
     * serialize/unserialize
     *
     * @return void
     */
    public static function clean()
    {
        static::$context = null;
    }
    

    Now I can clean up as required:

    use Foo\Custom\SerializableClosure;
    
    $bar = $foo;
    try {
        $bar = \Foo\Custom\unserialize($foo);
    } catch (Exception $e) {
        SerializableClosure::clean();
    }
    

    Now it cleans up after itself & allows future serialization.

    I'm mainly just reporting this in case its of use to you guys - but a couple of suggestions for your consideration:

    1. Ideally use a try/catch when serializing/unserializing & clean up the global state (before rethowing) in a catch block.
    2. Alternatively provide a clean method, or some other way to restore to a clean state / forcibly exit the current context as I've done above
    3. Perhaps you could consider adding an additional doc under "Good to know" or at least a note to https://opis.io/closure/3.x/context.html.
    opened by brentkelly 1
  • The DateTime object has not been correctly initialized by its constructor

    The DateTime object has not been correctly initialized by its constructor

    Hello,

    I encountered an issue with the following code:

    use function Opis\Closure\serialize;
    use Carbon\Carbon;
    
    serialize(Carbon::now());
    

    It works using a regular DateTime object.

    Carbon version: 2.58.0

    PHP version: 8.0.18

    opis version: 3.6.3

    I expected to get:

    a serialized carbon object as string

    But I actually get:

    Error
    The DateTime object has not been correctly initialized by its constructor
    

    Stack trace:

    local.ERROR: The DateTime object has not been correctly initialized by its constructor {"userId":4,"exception":"[object] (Error(code: 0): The DateTime object has not been correctly initialized by its constructor at /var/www/html/vendor/nesbot/carbon/src/Carbon/Traits/Converter.php:105)
    [stacktrace]
    #0 /var/www/html/vendor/nesbot/carbon/src/Carbon/Traits/Converter.php(105): DateTime->format()
    #1 /var/www/html/vendor/nesbot/carbon/src/Carbon/Traits/Converter.php(86): Carbon\\Carbon->rawFormat()
    #2 /var/www/html/vendor/nesbot/carbon/src/Carbon/Traits/Serialization.php(230): Carbon\\Carbon->format()
    #3 /var/www/html/vendor/nesbot/carbon/src/Carbon/Traits/Serialization.php(127): Carbon\\Carbon->getSleepProperties()
    #4 [internal function]: Carbon\\Carbon->__sleep()
    #5 /var/www/html/vendor/opis/closure/functions.php(20): serialize()
    #6 /var/www/html/routes/web.php(58): Opis\\Closure\\serialize()
    #7 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(238): Illuminate\\Routing\\RouteFileRegistrar->{closure}()
    #8 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(208): Illuminate\\Routing\\Route->runCallable()
    #9 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(721): Illuminate\\Routing\\Route->run()
    #10 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
    #11 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #12 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle()
    #13 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #14 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle()
    #15 /var/www/html/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #16 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle()
    #17 /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #18 /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest()
    #19 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Session\\Middleware\\StartSession->handle()
    #20 /var/www/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #21 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle()
    #22 /var/www/html/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #23 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle()
    #24 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #25 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(723): Illuminate\\Pipeline\\Pipeline->then()
    #26 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(698): Illuminate\\Routing\\Router->runRouteWithinStack()
    #27 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(662): Illuminate\\Routing\\Router->runRoute()
    #28 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(651): Illuminate\\Routing\\Router->dispatchToRoute()
    #29 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate\\Routing\\Router->dispatch()
    #30 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
    #31 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #32 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
    #33 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
    #34 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #35 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
    #36 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
    #37 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #38 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
    #39 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #40 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
    #41 /var/www/html/vendor/fruitcake/laravel-cors/src/HandleCors.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #42 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fruitcake\\Cors\\HandleCors->handle()
    #43 /var/www/html/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #44 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fideloper\\Proxy\\TrustProxies->handle()
    #45 /var/www/html/vendor/tenancy/identification-driver-http/Middleware/EagerIdentification.php(40): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #46 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Tenancy\\Identification\\Drivers\\Http\\Middleware\\EagerIdentification->handle()
    #47 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
    #48 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate\\Pipeline\\Pipeline->then()
    #49 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
    #50 /var/www/html/public/index.php(59): Illuminate\\Foundation\\Http\\Kernel->handle()
    #51 /var/www/html/server.php(21): require_once('...')
    #52 {main}
    "} 
    

    Thanks!

    opened by chWagnr 0
  • Should closures with `$this` keyword be wrapped in an additional closure?

    Should closures with `$this` keyword be wrapped in an additional closure?

    The examples in the docs referring to $this all use classes, but I just want to serialize a closure, not the entire class. I'm passing the following closure to the serializer

    function () use ($outerVar) {
    
    	return $outerVar . "/" . $this->myProperty;
    }
    

    And it throws the error "PDOException: You cannot serialize or unserialize PDO instances". I don't have a PDO instance anywhere close to where this closure is sent down to serializer. I realized other closures work without the $this keyword, combined with clues from reading other issues, I wrapped closure in additional closure

    function () use ($outerVar) {
    
    	return function () use ($outerVar) {
    
    		return $outerVar . "/" . $this->myProperty;
    	};
    }
    

    And error disappeared during serialization, but issue still stands. See next paragraph. I'm able to serialize and unserialize, but this doesn't seem to be intended use since I can't bind $this to context where closure is unserialized at. When I unserialize like so:

    public function evaluateClosure (callable $receivedClosure) {
    	$callable = unserialize($receivedClosure)->getClosure();
    
    	$callable->bindTo($this, $this); // so dev can have access to `myProperty`
    	// also tried ->bindTo(null)
    
    	var_dump($callable()); // returns the outer closure
    

    Then, going further to call $callable()() results in "Error: Using $this when not in object context". Is this a serialization problem or a binding one?

    opened by nmeri17 2
  • Fix serialization of DateTime object not working since php 7.1

    Fix serialization of DateTime object not working since php 7.1

    Starting at PHP 7.4 there is a bug that prevents the use of the ReflectionObject with a DateTime object, as the getProperties() method returns an empty array.

    @see https://bugs.php.net/bug.php?id=79041 @see https://3v4l.org/joLur

    For this reason and to avoid any issues, we can just skip the wrapping of DateTime objects.

    Related issue : #75

    @sorinsarca I hope this is OK to merge and release. I tested it locally and seems to work just fine. Also I guess this will be no issue anymore with the v4 that is in the works, but for now as I use this with Laravel, I cannot upgrade to the v4 so I would need this workaround.

    opened by iPurpl3x 8
  • Closure::fromCallable results in Call to a member function bindTo() on null

    Closure::fromCallable results in Call to a member function bindTo() on null

    Creating a closure from a callable before serialization causes an error when it is later unserialized. Both the callable and closure work apparently the same way, but there must be something different.

    I got to this test script:

    <?php
    
    declare(strict_types=1);
    
    use Opis\Closure\SerializableClosure;
    
    use function Opis\Closure\{serialize as s, unserialize as u};
    
    require __DIR__ . '/vendor/autoload.php';
    
    function test() {
        echo "Hello\n";
    }
    
    // These three are just working correctly
    'test'();
    u(s('test'))();
    unserialize(serialize('test'))();
    
    // If explicitly creating a closure, the closure works, but the serialization doesn't
    $closure = Closure::fromCallable('test');
    $closure();
    u(s($closure))();
    unserialize(serialize(new SerializableClosure($closure)))();
    

    When using Closure::fromCallable and then the serialization I got this error:

    PHP Fatal error:  Uncaught Error: Call to a member function bindTo() on null in vendor/opis/closure/src/SerializableClosure.php:263
    Stack trace:
    #0 [internal function]: Opis\Closure\SerializableClosure->unserialize()
    #1 vendor/opis/closure/functions.php(36): unserialize()
    #2 test3.php(23): Opis\Closure\unserialize()
    #3 {main}
      thrown in vendor/opis/closure/src/SerializableClosure.php on line 263
    

    I tried to find an example of using fromCallable in the documentation but I couldn't find one. Is it something I'm missing?

    opened by fcastilloes 1
  • Some time unserialize return false

    Some time unserialize return false

    i have some closure need to be serialized to run it in other server. I serialized it and save to redis, retrieve it from other server but it return false when unserialized?

    do you have any idea for this case?

    opened by nguyenngocanh94 0
Releases(3.6.3)
Owner
Opis
A fantastic collection of well crafted, developer-focused, open source libraries
Opis
A simple, standalone, modern PHP class inspector and mapper library, wrapping PHPs native reflection in a fluent interface

A simple, standalone, modern PHP class inspector and mapper library, wrapping PHPs native reflection in a fluent interface.

smpl 9 Sep 1, 2022
This car rental project system project in PHP focuses mainly on dealing with customers regarding their car rental hours and certain transactions.

Car-Rental Online Car Rental Management System This car rental project system project in PHP focuses mainly on dealing with customers regarding their

Adarsh Kumar Singh 2 Sep 29, 2022
JSON <=> PHP8+ objects serialization / deserialization library

A simple library for JSON to PHP Objects conversions Often times, we interact with an API, or data source that returns JSON. PHP only offers the possi

Square 90 Dec 20, 2022
A pure PHP implementation of the MessagePack serialization format / msgpack.org[PHP]

msgpack.php A pure PHP implementation of the MessagePack serialization format. Features Fully compliant with the latest MessagePack specification, inc

Eugene Leonovich 368 Dec 19, 2022
Dubbox now means Dubbo eXtensions, and it adds features like RESTful remoting, Kyro/FST serialization, etc to the Dubbo service framework.

Dubbox now means Dubbo eXtensions. If you know java, javax and dubbo, you know what dubbox is :) Dubbox adds features like RESTful remoting, Kyro/FST

当当 4.9k Dec 27, 2022
PHP remote closure executor

Jumper Allow you to execute PHP Closure in other distant computer via SSH and without client/server setup. Source computer dependency: PHP >= 5.3 (so

Thibaud Lepretre 45 Aug 11, 2022
Sslurp is a simple library which aims to make properly dealing with SSL in PHP suck less.

Sslurp v1.0 by Evan Coury Introduction Dealing with SSL properly in PHP is a pain in the ass and completely insecure by default. Sslurp aims to make i

Evan Coury 65 Oct 14, 2022
AnsibleBoy aims to use the Asnible `facts` as data, which can then be visualized in a table format

AnsibleBoy - Ansible Frontend Hub About AnsibleBoy aims to use the Ansible facts as data, which can then be visualized as a table ToDo (note that this

Ron 23 Jul 14, 2022
This module aims to validate if the pilot made his flights online on the IVAO and VATSIM networks

SMPirepValidator This module aims to validate if the pilot made his flights online on the IVAO and VATSIM networks SMPirepValidator v.1.0 for phpVMS (

SmartModules for phpVMS 1 Dec 13, 2021
This project aims to facilitate the management of websites monitored by the blackbox exporter, via a web UI.

This project aims to facilitate the management of websites monitored by the blackbox exporter, via a web UI. The UI would allow to add/remove sites, groups, and even add different fields in the prometheus database.

null 2 Nov 6, 2021
actionMaster is a new faction plugin that aims at flexibility and customization of the plugin by the user and the developers.

FactionMaster is a new faction plugin that aims at flexibility and customization of the plugin by the user and the developers. It includes all the basic functionality of a faction plugin and data storage in MySQL or SQLITE. This is done by adding an extension system and a translation system. FactionMaster has a will of accessibility to the players and especially not to have to remember a lot of commands to play, all is done via interface.

FactionMaster 21 Dec 26, 2022
Project that aims to create a website for a gym, where the clients and employees can access their data, buy in the gym store and check the gym activities.

Gym_Management_Project Project that aims to create a website for a gym, where the clients and employees can access their data, buy in the gym store an

null 1 Jan 12, 2022
🐋 This project aims to broaden knowledge of system administration by using Docker: virtualizing several Docker images, creating them in a new personal virtual machine.

?? This project aims to broaden knowledge of system administration by using Docker: virtualizing several Docker images, creating them in a new personal virtual machine.

Anton Kliek 1 Jan 26, 2022
This repository aims to build a fairly complete CI/CD example using GitHub workflows and actions.

CI/CD example This repository aims to build a fairly complete CI/CD example using GitHub workflows and actions. Keep in mind that the toolset used in

Robin Ingelbrecht 4 Nov 1, 2022
Dobren Dragojević 6 Jun 11, 2023
: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 532 Dec 25, 2022
Small convention based CQRS library for PHP

LiteCQRS for PHP Small naming-convention based CQRS library for PHP (loosely based on LiteCQRS for C#) that relies on the MessageBus, Command, EventSo

Benjamin Eberlei 560 Nov 20, 2022
Experimental library for forking PHP

Spork: PHP on a Fork <?php $manager = new Spork\ProcessManager(); $manager->fork(function() { // do something in another process! return 'Hel

Kris Wallsmith 588 Nov 20, 2022
Collection pipeline library for PHP

Knapsack Collection pipeline library for PHP Knapsack is a collection library for PHP >= 5.6 that implements most of the sequence operations proposed

Dušan Kasan 540 Dec 17, 2022