• Eric Muyser

    "The two most important days in your life are the day you are born... and the day you find out why." - Mark Twain

    At the moment PHP doesn’t allow serializing closures. I needed a unobtrusive solution to passing closures to child processes, which are invoked later when the child process has completed the task.

    I came across an informational article Jeremy Lindblom wrote on closures in PHP 5 over at HTMList which helped me come up with a solution to my problem. I didn’t end up needing to save the serialized closure for a different process (or HTTP request), but it looks like a very interesting solution.

    For my purposes I can keep references to actual closures in the main process, and they will function exactly as they should later (including use references). An example is a cron which goes through a list of videos, spawns an FFMPEG encoding process, sends a job off to it with a lambda callback. It’s all very smooth and asynchronous. Another example is a DNS checking service (since IIRC, DNS requests are not currently asynchronous in PHP).

     

    Example:

    1.  
    2.  
    3. $a1 = array();

    4. $some_function_called_later(new lambda(function() use(&$a1)

    5. {

    6. var_dump($a1); // will contain "info" added later below

    7. }));

    8. $a1[] = "info";

     

    Source:

    1.  
    2.  
    3. <?php

    4. class resource_service

    5. {

    6. public static function register(&$resource)

    7. {

    8. $id = rand(0, 32768);

    9. while(isset(self::$registry[$id]))

    10. $id = rand(0, 32768);

    11. self::$registry[$id] = &$resource;

    12. return $id;

    13. }

    14. public static function unregister($id)

    15. {

    16. $resource = &self::$registry[$id];

    17. unset(self::$registry[$id]);

    18. return $resource;

    19. }

    20. private static $registry;

    21. }

    22. class lambda

    23. {

    24. public function construct(Closure $closure)

    25. {

    26. $this->closure = $closure;

    27. }

    28. public function invoke()

    29. {

    30. return call_user_func_array($this->closure, func_get_args());

    31. }

    32. public function sleep()

    33. {

    34. $this->resource_id = resource_service::register($this->closure);

    35. return array("resource_id");

    36. }

    37. public function wakeup()

    38. {

    39. $this->closure = &resource_service::unregister($this->resource_id);

    40. }

    41. private $closure;

    42. }

    43. ?>

     

    More found on the work page, and more to come!