Laravel Serializable Closure provides an easy way to serialize closures in PHP.

Overview

Serializable Closure

Build Status Total Downloads Latest Stable Version License

Introduction

This package is a work in progress

Laravel Serializable Closure provides an easy way to serialize closures in PHP. It's a fork of opis/closure: ^3.0 that does not use the PHP FFI Extension, and supports PHP 8.1.

Installation / Usage

Requires PHP 7.3+

First, install Laravel Serializable Closure via the Composer package manager:

composer require laravel/serializable-closure --dev

Then, you may serialize a closure this way:

use Laravel\SerializableClosure\SerializableClosure;

$closure = fn () => 'james';

SerializableClosure::setSecretKey('secret');

$serialized = serialize(new SerializableClosure($closure));
$closure = unserialize($serialized)->getClosure();

echo $closure(); // james;

License

Seriazable Closure is open-sourced software licensed under the MIT license.

Comments
  • fix: serializing date and carbon objects

    fix: serializing date and carbon objects

    When trying to serialize properties that have date objects or carbon objects like when queuing a closure, I'm facing bugs/warnings similar to this:

    • PHP Warning: serialize(): "date" returned as member variable from __sleep()
    • The DateTime object has not been correctly initialized by its constructor

    I found that the issue is with serializing the date objects and php version. Also found similar PRs. https://github.com/opis/closure/issues/75 https://github.com/opis/closure/pull/113

    opened by yamenarahman 6
  • Error: File name too long[36]

    Error: File name too long[36]

    • Serializable Closure Version: 1.0.5
    • Laravel Version: 8.81.0
    • PHP Version: 8.1.1
    • Database Driver & Version: MariaDB 10.6

    Description:

    Using Octane to run some concurrent functions I get the following : [2022-02-01 14:31:06 ^76940.11] WARNING Server::task_unpack(): open(ravel\SerializableClosure\SerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Signed":2:{s:12:"serializable";s:721:"O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:2:{s:11:"current_job";O:45:"Illum) failed, Error: File name too long[36]

    Steps To Reproduce:

    
    Octane::concurrently([
                        fn () => (isset($track_input[0]) ? $this->jobtrack->insert($track_input) : null),
                        function () use ($image_input, $document_input) {
                            $this->job_images->insert($image_input);
                            $this->job_documents->insert($document_input);
                        }
                    ]);
    
    needs more info 
    opened by maher1337 6
  • Call to undefined method Laravel\SerializableClosure\Serializers\Native::from()

    Call to undefined method Laravel\SerializableClosure\Serializers\Native::from()

    • Serializable Closure Version: 1.0.0
    • Laravel Version: 8.62.0
    • PHP Version: 8.0.11
    • Database Driver & Version: -

    Description:

    I get Call to undefined method Laravel\SerializableClosure\Serializers\Native::from() when I serialize a closure that is using a $this object that contains closures.

    Steps To Reproduce:

    class BindToMe
    {
        private Closure $closure;
    
        public function __construct(Closure $closure)
        {
            $this->closure = $closure;
        }
    
        public function hello()
        {
            echo ($this->closure)();
        }
    }
    
    $serializable = new \Laravel\SerializableClosure\SerializableClosure(
        Closure::bind(
            function () {
                $this->hello();
            },
            new BindToMe(fn() => 'Hi')
        )
    );
    
    serialize($serializable);
    
    bug 
    opened by henze-housepedia 6
  • Skip readonly properties

    Skip readonly properties

    The current will attempt to do $property->setValue($data, $item) which in the case of a readonly property will result into failure.

    Having a glance at the tests it appears this should already be supported in theory, but I am running into this issue with laravel/serializable-closure v1.2.2 with PHP-Scoper. So this needs deeper investigation

    needs more info 
    opened by theofidry 5
  • PHP Error:  Call to a member function bindTo() on null

    PHP Error: Call to a member function bindTo() on null

    • Serializable Closure Version: dev-master (e4970ee)
    • Laravel Version: 8.75
    • PHP Version: 8.0.15
    • Database Driver & Version: mysql

    Description:

    I have a very similar problem to this one here: https://github.com/laravel/serializable-closure/issues/32

    However, latest commit doesn't seem to be working for me.

    Steps To Reproduce:

    composer create-project laravel/laravel test
    php artisan queue:batches-table
    php artisan migrate
    composer require laravel/serializable-closure:dev-master
    

    Then >>

    ➜  php artisan tinker
    Psy Shell v0.11.1 (PHP 8.0.15 — cli) by Justin Hileman
    >>> \Illuminate\Support\Facades\Bus::batch([])->name("test2")->then(function ($b) {
    ... echo 'asd';
    ... })->dispatch();
    <warning>PHP Warning:  file_get_contents(/Users/user/work/testeval()'d code): Failed to open stream: No such file or directory in /Users/user/work/test/vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php on line 805</warning>
    PHP Error:  Call to a member function bindTo() on null in /Users/user/work/test/vendor/laravel/serializable-closure/src/Serializers/Native.php on line 193
    
    
    

    Passing an array with a job to the batch method also gives the same result.

    needs more info 
    opened by suhaboncukcu 5
  • Job chain can't serialize named argument in closure (Parsing error)

    Job chain can't serialize named argument in closure (Parsing error)

    • Laravel Version: 8.73.2
    • PHP Version: 8.0.7
    • Database Driver & Version: mysql Ver 8.0.22 for osx10.16 on x86_64 (Homebrew)

    Description:

    The closure fails to serialize with:

    syntax error, unexpected token ":", expecting ")" {"userId":7,"exception":"[object] (ParseError(code: 0): syntax error, unexpected token \":\", expecting \")\" at laravel-serializable-closure://fn () => $this->requestUpdate(
        \\App\\Models\\clearCollectionCache: false,
        \\App\\Jobs\\Duda\\RefreshSite: true,
    ):3)
    
    Bus::chain([
        new CreateSite($this),
        fn () => $this->requestUpdate(
            clearCollectionCache: false,
            refreshSite: true,
        ),
    ])->dispatch();
    

    Steps To Reproduce:

    Just add a closure with a named argument call inside and it will fail to parse. Example above.

    Workaround

    Remove the named argument:

    Bus::chain([
        new CreateSite($this),
        fn () => $this->requestUpdate(false, true),
    ])->dispatch();
    
    bug 
    opened by ConsoleTVs 5
  • Added failing test for PHP8 attributes

    Added failing test for PHP8 attributes

    Description

    It seems like PHP8 Attributes are not properly serialized. When serializing a closure that was annotated with attributes, those cannot be received using ReflectionFunction::getAttributes() on the deserialized one (as shown by the test).

    At the moment, Laravel does not use any attributes to change route behavior, but I can see this being useful in the future (for an example, see "Motivation"). If this is not intended to be supported, I feel like this should be at least documented in the "Caveats"-section of the Readme.

    Motivation

    I tried to build a package that does something similar to this closed PR on the laravel framework. Basically you configure a middleware, annotate your controller/closure with an Transactional-attribute, and they will automatically be wrapped in a transaction:

    // web.php
    Route::get('transactional', #[Transactional] function () {
        $a = User::factory()->create();
        $b = User::factory()->create();
    
        return [$a, $b];
    }
    

    This code works fine during development, but as soon as I run php artisan optimize and the route files are cached, the Transactional attribute disappears, and the function is not wrapped inside a transaction anymore. This is due to the behavior shown in the test.

    opened by NiclasvanEyk 4
  • Support for PHP 8.1 enums

    Support for PHP 8.1 enums

    Hi, good job with this fork!

    I recently ran into a situation, where a class has an enum property, which prevents the call to ReflectionClass->newInstanceWithoutConstructor(), since an enum cannot be instantiated:

    PHP Fatal error:  Uncaught Error: Cannot instantiate enum Project\AnEnum in ...\vendor\laravel\serializable-closure\src\Serializers\Native.php:261
    Stack trace:
    #0 ...\vendor\laravel\serializable-closure\src\Serializers\Native.php(261): ReflectionClass->newInstanceWithoutConstructor()
    #1 ...\vendor\laravel\serializable-closure\src\Serializers\Native.php(282): Laravel\SerializableClosure\Serializers\Native::wrapClosures(Object(Project\AnEnum), Object(Laravel\SerializableClosure\Support\ClosureScope))
    #2 ...\vendor\laravel\serializable-closure\src\Serializers\Native.php(122): Laravel\SerializableClosure\Serializers\Native::wrapClosures(Object(Project\ParentClass), Object(Laravel\SerializableClosure\Support\ClosureScope))
    #3 [internal function]: Laravel\SerializableClosure\Serializers\Native->__serialize()
    ...
    

    Any intention of supporting this use-case?

    needs more info 
    opened by ricardoboss 4
  • Class not found when type-hint is defined for closure created from method

    Class not found when type-hint is defined for closure created from method

    • Serializable Closure Version: v1.1.0
    • Laravel Version: not laravel scope
    • PHP Version: 8.0.15

    Description:

    I created closure from object method and tried to serialize it, however once unserialized it fails because of type hint used for this method.

    Steps To Reproduce:

    Minimal code example is below:

    Entry point script:

    <?php
    
    use Laravel\SerializableClosure\SerializableClosure;
    use Rela589n\PhpDecorationIssue\SerializableClosure\SerializableClosureIssue;
    
    require 'vendor/autoload.php';
    
    $object = new SerializableClosureIssue();
    
    /** @var SerializableClosure $original */
    $original = unserialize(
        serialize(
            new SerializableClosure(Closure::fromCallable([$object, 'reproduceIssue']))
        )
    );
    
    var_dump($original->getClosure()());
    

    Class with method which will be used as closure:

    <?php
    
    declare(strict_types=1);
    
    namespace Rela589n\PhpDecorationIssue\SerializableClosure;
    
    use JetBrains\PhpStorm\Immutable;
    
    #[Immutable]
    final class SerializableClosureIssue
    {
        public function reproduceIssue(): Issue
        {
            return new Issue();
        }
    }
    

    Class for type-hinting in method:

    <?php
    
    declare(strict_types=1);
    
    namespace Rela589n\PhpDecorationIssue\SerializableClosure;
    
    use JetBrains\PhpStorm\Immutable;
    
    #[Immutable]
    final class Issue
    {
    
    }
    

    The foregoing code gives next issue:

    PHP Fatal error:  Uncaught Error: Class "Issue" not found in laravel-serializable-closure://function (): \Issue
        {
            return new \Issue();
        }:4
    Stack trace:
    #0 /home/rela589n/projects/php-decoration-issue/serializable-closure.php(17): Rela589n\PhpDecorationIssue\SerializableClosure\SerializableClosureIssue::{closure}()
    #1 {main}
      thrown in laravel-serializable-closure://function (): \Issue
        {
            return new \Issue();
        } on line 4
    

    Thanks

    Thank you for this amazing package, it really complements missing PHP feature.

    opened by rela589n 4
  • Call to a member function `bindTo()` on `null`

    Call to a member function `bindTo()` on `null`

    • Serializable Closure Version: 1.2.2
    • Laravel Version: 9.40.1
    • PHP Version: 8.1.12
    • Database Driver & Version: postgres 14

    Description:

    I was working on implementing batched jobs using Bus::batch when I noticed that chaining any completion callbacks will throw an error

    Call to a member function bindTo() on null

    image

    Note Extracting the closure from ->then to a protected function then calling it works 🤷‍♂️ like ->then($this->notifyOwner())

    I tried it with Tinker, and I got the same results, so I tried to simplify the work and tested the example stated in the readme file here using both Tinkerwell and tinker with the same results.

    Psy Shell v0.11.9 (PHP 8.1.12 — cli) by Justin Hileman
    > use Laravel\SerializableClosure\SerializableClosure;
    > $closure = fn () => 'james';
    = Closure() {#5091 …2}
    
    > SerializableClosure::setSecretKey('secret');
    = null
    
    > $serialized = serialize(new SerializableClosure($closure));
    
       WARNING  file_get_contents(eval()'d code): Failed to open stream: No such file or directory in vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php on line 829.
    
    = "O:47:"Laravel\SerializableClosure\SerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Signed":2:{s:12:"serializable";s:174:"O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:0:{}s:8:"function";s:0:"";s:5:"scope";N;s:4:"this";N;s:4:"self";s:32:"00000000000013e30000000000000000";}";s:4:"hash";s:44:"A3kjjoOaJHAtn4QzC61Wx//EuVlbAb8Q6PmTlStglb8=";}}"
    
    > $closure = unserialize($serialized)->getClosure();
    
       ERROR  Call to a member function bindTo() on null in vendor/laravel/serializable-closure/src/Serializers/Native.php on line 194.
    
    

    image

    Steps To Reproduce:

    Open tinker and try the usage example listed here

    bug 
    opened by zaherg 3
  • Issue with implicitly imported class type hint

    Issue with implicitly imported class type hint

    This pull request adds tests for closure created from object method, which defines type-hint of object residing in the same namespace, which is therefore imported implicitly.

    opened by rela589n 3
Releases(v1.2.2)
Owner
The Laravel Framework
The Laravel Framework
Make Laravel Pivot Tables using the new Laravel 9 closure migration format

This will allow you to create pivot table migration files using the new Laravel 9 closure migration format by simply passing two models.

Jose Jimenez 16 Aug 23, 2022
Laravel Boilerplate provides a very flexible and extensible way of building your custom Laravel applications.

Laravel Boilerplate Project Laravel Boilerplate provides a very flexible and extensible way of building your custom Laravel applications. Table of Con

Labs64 848 Dec 28, 2022
Laravel Breadcrumbs - An easy way to add breadcrumbs to your @Laravel app.

Introduction Breadcrumbs display a list of links indicating the position of the current page in the whole site hierarchy. For example, breadcrumbs lik

Alexandr Chernyaev 269 Dec 21, 2022
Otpify is a Laravel package that provides a simple and elegant way to generate and validate one time passwords.

Laravel Otpify ?? Introduction Otpify is a Laravel package that provides a simple and elegant way to generate and validate one time passwords. Install

Prasanth Jayakumar 2 Sep 2, 2022
An easy way to integrate Google Maps with Laravel

An easy way to integrate Google Maps with Laravel For Laravel 5.x, check version 2.35.1 For Laravel 4.x, check version 1.27.0 Think of Googlmapper as

Bradley Cornford 450 Nov 29, 2022
Easy way to upload Laravel model related files from the request.

Easy way to upload laravel model related file from the requset.

Emon Khan 5 Dec 15, 2022
Easy Way to integrate API in you laravel application.

Easy Api Easy Way to integrate API in you laravel application. Installation Guide Install Package using Composer. composer require flutterbuddy1/easy-

Mayank Diwakar 1 Oct 9, 2022
Laravel User Activity Log - a package for Laravel 8.x that provides easy to use features to log the activities of the users of your Laravel app

Laravel User Activity Log - a package for Laravel 8.x that provides easy to use features to log the activities of the users of your Laravel app

null 9 Dec 14, 2022
Kalibrant - a package that provides a simple way to manage your models settings

Introduction For your laravel 9.x applications, Kalibrant is a package that provides a simple way to manage your models settings. It is a simple way t

Starfolk 3 Jun 18, 2022
🏭 An easy way to generate populated factories for models.

Laravel Populated Factory provides an easy way to generate populated factories for models according to types & names of their columns. Install You can

Coderello 241 Nov 25, 2022
An easy way to add colors in your CLI scripts.

COLORS Here is a preview of what you can achieve with the library: Installation Installation via composer is highly recommended. { "require": {

Kevin Le Brun 335 Dec 4, 2022
An easy way to get vendor and package data from Packagist via API calls

Laravel Packagist Laravel Packagist (LaravelPackagist) is a package for Laravel 5 to interact with the packagist api quickly and easily. Table of cont

Jeremy Kenedy 5 Jul 18, 2022
Laravel Package for TMDB ( The Movie Database ) API. Provides easy access to the wtfzdotnet/php-tmdb-api library.

Laravel Package for TMDB API Wrapper A Laravel package that provides easy access to the php-tmdb/api TMDB (The Movie Database) API wrapper. This packa

PHP - The Movie Database 151 Nov 1, 2022
Laravel-tagmanager - An easier way to add Google Tag Manager to your Laravel application.

Laravel TagManager An easier way to add Google Tag Manager to your Laravel application. Including recommended GTM events support. Requirements Laravel

Label84 16 Nov 23, 2022
Laravel Logable is a simple way to log http request in your Laravel application.

Laravel Logable is a simple way to log http request in your Laravel application. Requirements php >= 7.4 Laravel version >= 6.0 Installation composer

Sagar 6 Aug 25, 2022
An Eloquent Way To Filter Laravel Models And Their Relationships

Eloquent Filter An Eloquent way to filter Eloquent Models and their relationships Introduction Lets say we want to return a list of users filtered by

Eric Tucker 1.5k Jan 7, 2023
Save Model is a Laravel package that allows you to save data in the database in a new way.

Save Model is a Laravel package that allows you to save data in the database in a new way. No need to worry about $guarded and $fillable properties in the model anymore. Just relax an use Save Model package.

Laratips 27 Mar 2, 2022
A Laravel package to manage versions of endpoints in an elegant way

API version control A Laravel package to manage versions of endpoints in an elegant way Two ways to manage the versions of your endpoints Option 1: Ve

Reindert 156 Dec 9, 2022
A laravel package to handle model specific additional meta fields in an elegant way.

Laravel Meta Fields A php package for laravel framework to handle model meta data in a elegant way. Installation Require the package using composer: c

Touhidur Rahman 26 Apr 5, 2022