Both sides previous revisionPrevious revisionNext revision | Previous revision |
rfc:closures:object-extension [2010/08/11 13:25] – bindTo changes cataphract | rfc:closures:object-extension [2017/09/22 13:28] (current) – external edit 127.0.0.1 |
---|
====== Closures: Object extension ====== | ====== Closures: Object extension ====== |
| * Date: 2009-01-22 |
| * Author: Unknown |
| * Status: Implemented in PHP 5.4 |
| |
| ===== Introduction ===== |
| |
Efforts were made to go beyond the scope of the original Closures proposal ([[rfc/closures]]) in order to allow the extension of objects dynamically, take the following example code: | Efforts were made to go beyond the scope of the original Closures proposal ([[rfc/closures]]) in order to allow the extension of objects dynamically, take the following example code: |
==== Private/protected members (scope) ==== | ==== Private/protected members (scope) ==== |
| |
The currently implemented handling of scope for class closures is | The currently implemented handling of scope for class closures is: |
| |
- They initially inherit the (calling) scope of the class they were created in. | - They initially inherit the (calling) scope of the class they were created in. |
- After that, always use the class scope of the object that bindTo() is called for ([[#private_protected_member_access|option 2]]) | - After that, always use the class scope of the object that bindTo() is called for ([[#private_protected_member_access|option 2]]) |
- If there's any bound instance, the called scope is set to the class of it, otherwise it's the same as the calling scope. | - If there's any bound instance, the called scope is set to the class of it, otherwise it's the same as the calling scope. |
| |
The implementation of option #2 has serious drawbacks. Consider the following code: | The implementation of option #2 has serious drawbacks. Consider the following code: |
There's always another problem. The current implementation allows changing the scope of a static closure, but only by attempting to bind it with am object of the desired class. This has two problems: it requires an instance for a solely static operation and it may even not be possible to generate objects of the desired class (e.g. it's abstract). | There's always another problem. The current implementation allows changing the scope of a static closure, but only by attempting to bind it with am object of the desired class. This has two problems: it requires an instance for a solely static operation and it may even not be possible to generate objects of the desired class (e.g. it's abstract). |
| |
Therefore, I propose an implementation ([[http://nebm.ist.utl.pt/~glopes/misc/closures_scope.patch|patch here]]) of option 4: "Add a parameter to bindTo() to specify this." This option is the most versatile and the implementation in the patch has very little magic – it only changes the scope of the closure if it's requested, otherwise it keeps the previous scope. The order of the current arguments of ''Closure::bind'' was also changed so that its implementation could be unified to that of ''Closure::bindTo'' using ''zend_parse_method_parameters''. The prototype is this: | Therefore, I propose an implementation ([[http://nebm.ist.utl.pt/~glopes/misc/closures_scope.patch|patch here]]) of option #4: "Add a parameter to bindTo() to specify this." This option is the most versatile and the implementation in the patch has very little magic – it only changes the scope of the closure if it's requested, otherwise it keeps the previous scope. The order of the current arguments of ''Closure::bind'' was also changed so that its implementation could be unified to that of ''Closure::bindTo'' using ''zend_parse_method_parameters''. The prototype is this: |
| |
<code> | <code> |
| |
The patch preserves these invariants: | The patch preserves these invariants: |
- A static closure, being scoped or not, cannot have any bound instance. | - A static closure, being scoped or not, cannot have any bound instance. |
- A non static closure has a bound instance iif it is scoped. | - A non static closure has a bound instance iif it is scoped. |
| |
To preserve these invariants, there are these additional rules: | To preserve these invariants, there are these additional rules: |
- If a non static closure is given a scope (or it already has a scope, but the scope parameter is not specified) and a NULL instance, it's made static. | - If a non static closure is given a scope (or it already has a scope, but the scope parameter is not specified) and a NULL instance, it's made static. |
- If a static closure is given an instance, the instance is ignored and an ''E_WARNING'' notice is emitted. | - If a static closure is given an instance, the instance is ignored and an ''E_WARNING'' notice is emitted. |
- If a non static non scoped (and therefore non bound) instance is given no scope and a non NULL instance, it's given a dummy scope (currently the "Closure" scope). **This is the only case where the previous scope, or lack thereof, is changed by the rebinding process**. This is necessary because it's not legal to have ''$this'' with a NULL scope. | - If a non static non scoped (and therefore non bound) instance is given no scope and a non NULL instance, it's given a dummy scope (currently the "Closure" scope). **This is the only case where the previous scope, or lack thereof, is changed by the rebinding process**. This is necessary because it's not legal to have ''$this'' with a NULL scope. |
| |
Example: | Example: |