rfc:closures

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
rfc:closures [2008/07/03 10:09] – Typos rquadlingrfc:closures [2009/12/15 22:40] – Fix list numbering rquadling
Line 3: Line 3:
   * Date: 2008-07-01   * Date: 2008-07-01
   * Author: Christian Seiler <chris_se@gmx.net>, Dmitry Stogov <dmitry@zend.com>   * Author: Christian Seiler <chris_se@gmx.net>, Dmitry Stogov <dmitry@zend.com>
-  * Status: Under Discussion+  * Status: Implemented
  
 This RFC discusses the introduction of compile-time lambda functions and closures in PHP. This RFC discusses the introduction of compile-time lambda functions and closures in PHP.
Line 16: Line 16:
  
 Closures and lambda functions can make programming much easier in several ways: Closures and lambda functions can make programming much easier in several ways:
- 
 ==== Lambda Functions ==== ==== Lambda Functions ====
  
-Lambda functions allow the quick definition of throw-away functions that are not used elsewhere. Imaging for example a piece of code that needs to call preg_replace_callback(). Currently, there are three possibilities to achieve this: +Lambda functions allow the quick definition of throw-away functions that are not used elsewhere. Imagine for example a piece of code that needs to call preg_replace_callback(). Currently, there are three possibilities to achieve this: 
- +  - Define the callback function elsewhere. This distributes code that belongs together throughout the file and decreases readability. 
-   - Define the callback function elsewhere. This distributes code that belongs together throughout the file and decreases readability. +  - Define the callback function in-place (but with a name). In that case one has to use function_exists() to make sure the function is only defined once. Here, the additional if() around the function definition makes the source code difficult to read. Example code:<code php>
- +
-   - Define the callback function in-place (but with a name). In that case one has to use function_exists() to make sure the function is only defined once. Here, the additional if() around the function definition makes the source code difficult to read. Example code: +
- +
-<code php>+
    function replace_spaces ($text) {    function replace_spaces ($text) {
      if (!function_exists ('replace_spaces_helper')) {      if (!function_exists ('replace_spaces_helper')) {
Line 35: Line 30:
    }    }
 </code> </code>
- +  - Use the present create_function() in order to create a function at runtime. This approach has several disadvantages: First of all, syntax highlighting does not work because a string is passed to the function. It also compiles the function at run time and not at compile time so opcode caches can't cache the function.
-   - Use the present create_function() in order to create a function at runtime. This approach has several disadvantages: First of all, syntax highlighting does not work because a string is passed to the function. It also compiles the function at run time and not at compile time so opcode caches can't cache the function.+
  
 ==== Closures ==== ==== Closures ====
Line 61: Line 55:
  
 The following proposal and patch implement compile-time lambda functions and closures for PHP while keeping the patch as simple as possible. The following proposal and patch implement compile-time lambda functions and closures for PHP while keeping the patch as simple as possible.
- 
 ==== Userland perspective ==== ==== Userland perspective ====
  
Line 97: Line 90:
      return preg_replace_callback ('/( +) /', $replacement, $text);      return preg_replace_callback ('/( +) /', $replacement, $text);
    }    }
 +</code>
 +
 +You can even put the lambda function inline, for example:
 +
 +<code php>
 +  function replace_spaces ($text) {
 +    return preg_replace_callback ('/( +) /',
 +      function ($matches) {
 +        return str_replace ($matches[1], ' ', '&nbsp;').' ';
 +      }, $text);
 +  }
 </code> </code>
  
Line 120: Line 124:
        }        }
      };      };
-     return array_map ($map, array);+     return array_map ($map, $array);
    }    }
 </code> </code>
Line 162: Line 166:
  
 === Interaction with OOP === === Interaction with OOP ===
 +
 +$this support has been removed, see [[rfc/closures/removal-of-this|removal of this]]
  
 If a closure is defined inside an object, the closure has full access to the current object through $this (without the need to import it explicitly) and all private and protected methods of that class. This also applies to nested closures. Example: If a closure is defined inside an object, the closure has full access to the current object through $this (without the need to import it explicitly) and all private and protected methods of that class. This also applies to nested closures. Example:
Line 200: Line 206:
          $x = 4;          $x = 4;
          $closure = static function ($y) use ($x) {          $closure = static function ($y) use ($x) {
-           return $x + $y;+           return $x + $y;
          };          };
          return $closure (6);          return $closure (6);
Line 208: Line 214:
  
 In this case, $this is not available inside the closure. This may save a lot of memory if saves many closures that originated in longer needed objects. In this case, $this is not available inside the closure. This may save a lot of memory if saves many closures that originated in longer needed objects.
 +
  
 ==== Additional goody: _ _invoke ==== ==== Additional goody: _ _invoke ====
Line 223: Line 230:
 </code> </code>
  
-==== Interaction with reflection ====+==== Interaction with reflection (1) ====
  
 Since closures are anonymous, they do **not** appear in reflection. Since closures are anonymous, they do **not** appear in reflection.
Line 256: Line 263:
 $object->x = 5; $object->x = 5;
 $closure (); $closure ();
 +</code>
 +
 +==== Interaction with reflection (2) ====
 +
 +In addition to the previous patch, reflection support was augmented to support reflecting closure objects and returning the correct function pointer.
 +
 +<code php>
 +$closure = function ($a, &$b, $c = null) { };
 +$m = new ReflectionMethod ($closure, '__invoke');
 +Reflection::export ($m);
 +</code>
 +
 +This will yield:
 +
 +<code>
 +Method [ <internal> public method __invoke ] {
 +
 +  - Parameters [3] {
 +    Parameter #0 [ <required> $a ]
 +    Parameter #1 [ <required> &$b ]
 +    Parameter #2 [ <optional> $c ]
 +  }
 +}
 +</code>
 +
 +The following will also work (invoke is implied if no method name is specified):
 +
 +<code php>
 +$m = new ReflectionMethod ($closure);
 +$p = new ReflectionParameter ($closure, 0);
 +$p = new ReflectionParameter ($closure, 'a');
 +$p = new ReflectionParameter (array ($closure, '__invoke'), 0);
 </code> </code>
  
Line 279: Line 318:
  
 ==== The patch ==== ==== The patch ====
 +
 +**Note:** The patches were already applied to PHP_5_3 and HEAD (with some minor modifications and fixes).
  
 Current patches: Current patches:
Line 300: Line 341:
 ==== BC breaks ==== ==== BC breaks ====
  
-   None by designA new previously invalid syntax is added. No additional keywords are defined.+   Creates an additional class named "Closure" that may break existing code. Apparently classes by this name [[http://google.com/codesearch?hl=en&lr=&q=%22class+Closure%22+lang%3Aphp&sbtn=Search|are used to emulate closures]] in current PHP versions. 
 +   * None otherwise (no new keywords)
  
 ==== Caveats / possible WTFs ==== ==== Caveats / possible WTFs ====
Line 311: Line 353:
  
 As the discussion on the mailing list showed, there were quite a few misconceptions on what closures may or may not achieve. One often used suggestion was to use closures in order to extend classes by additional methods at run time. This is **not** the goal of closures **and** it can already be achieved without closures just by using _ _call, see for example [[http://phpfi.com/328105]]. As the discussion on the mailing list showed, there were quite a few misconceptions on what closures may or may not achieve. One often used suggestion was to use closures in order to extend classes by additional methods at run time. This is **not** the goal of closures **and** it can already be achieved without closures just by using _ _call, see for example [[http://phpfi.com/328105]].
 +
 +===== Example code =====
 +
 +The example code in this document is available [[http://www.christian-seiler.de/temp/php-5.3-test-closures.txt|here]].
  
 ===== Changelog ==== ===== Changelog ====
  
 +   * 2008-08-11 Christian Seiler: Documented additional reflection improvements (see php-internals)
 +   * 2008-07-15 Christian Seiler: Updated status of this RFC
    * 2008-07-01 Christian Seiler: Updated patch yet again    * 2008-07-01 Christian Seiler: Updated patch yet again
    * 2008-06-26 Christian Seiler: Revised patch, using objects instead of resources, added tests    * 2008-06-26 Christian Seiler: Revised patch, using objects instead of resources, added tests
Line 321: Line 369:
    * 2008-06-16 Christian Seiler: Small changes    * 2008-06-16 Christian Seiler: Small changes
    * 2008-06-16 Christian Seiler: Initial creation    * 2008-06-16 Christian Seiler: Initial creation
- 
rfc/closures.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1