rfc:userspace_operator_overloading
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
rfc:userspace_operator_overloading [2020/02/15 21:01] – jbtronics | rfc:userspace_operator_overloading [2020/03/23 17:53] – jbtronics | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Userspace operator overloading ====== | ====== PHP RFC: Userspace operator overloading ====== | ||
- | * Version: 0.3 | + | * Version: 0.5 |
* Date: 2020-02-01 | * Date: 2020-02-01 | ||
* Author: Jan Böhmer, jan.h.boehmer@gmx.de | * Author: Jan Böhmer, jan.h.boehmer@gmx.de | ||
- | * Status: | + | * Status: |
- | * First Published at: http://wiki.php.net/rfc/userspace_operator_overloading | + | * Target Version: PHP 8.0 |
+ | * Implementation: | ||
===== Introduction ===== | ===== Introduction ===== | ||
At the moment expressions like '' | At the moment expressions like '' | ||
Line 25: | Line 26: | ||
Operator overloading is done by static magic functions per operator in a class. These functions receive both operands and must return a non null value: | Operator overloading is done by static magic functions per operator in a class. These functions receive both operands and must return a non null value: | ||
<PHP> | <PHP> | ||
- | public | + | class Vector3() |
{ | { | ||
- | | + | public static function __add($lhs, $rhs) { |
- | | + | |
// Do something with the values and return a non-null value | // Do something with the values and return a non-null value | ||
- | // ... | ||
} | } | ||
| | ||
- | public static function __mul($lhs, $rhs) { | + | public static function __mul($lhs, $rhs): ? |
- | // For more complex type checking, the function can return a special const. | + | // If the given types are not supported, the function can return a special const. |
//... | //... | ||
return PHP_OPERAND_TYPES_NOT_SUPPORTED; | return PHP_OPERAND_TYPES_NOT_SUPPORTED; | ||
Line 45: | Line 44: | ||
// Equivalent to $x = Vector3:: | // Equivalent to $x = Vector3:: | ||
$x = $a + $b; | $x = $a + $b; | ||
- | // | + | // |
$y = 3 * $b; | $y = 3 * $b; | ||
</ | </ | ||
Line 51: | Line 50: | ||
By passing both operands to the handler, it can decide between the cases on non-commutative operators ('' | By passing both operands to the handler, it can decide between the cases on non-commutative operators ('' | ||
- | The magic function can accept any type, the function has to decide if it can handle the type (and the value). If it can not handle the given type, it has to return the constant '' | + | The magic function can accept any type, the function has to decide if it can handle the type (and the value). If it can not handle the given type, it has to return the constant '' |
+ | |||
+ | The argument **must not** specify any argument typehints (an error is thrown otherwise), as typehints and occuring type errors would break operator evaluation ([[https:// | ||
+ | |||
+ | Handlers **can** specify return typehints, but note that the return type has to be nullable (as PHP_OPERAND_TYPES_NOT_SUPPORTED has the value null). | ||
==== Overloadable Operators ==== | ==== Overloadable Operators ==== | ||
- | Like mentioned above only basic arithmetic operators should be overloadable, | + | === Direct overloadable operators === |
+ | |||
+ | Like mentioned above only basic arithmetic operators should be overloadable, | ||
| ^ Operator | | ^ Operator | ||
Line 62: | Line 67: | ||
^ Division | ^ Division | ||
^ Power | '' | ^ Power | '' | ||
- | ^ Modulo | + | ^ Modulo |
^ Concatenation | ^ Concatenation | ||
- | ^ Bitwise shift left | ''<<'' | + | ^ Bitwise shift left | '' |
- | ^ Bitwise shift right | ''>>'' | + | ^ Bitwise shift right | '' |
- | ^ Bitwise OR | '' | + | ^ Bitwise OR | '' |
- | ^ Bitwise AND | ''&'' | + | ^ Bitwise AND | ''&'' |
- | ^ Bitwise XOR | '' | + | ^ Bitwise XOR | '' |
- | ^ Bitwise NOT | '' | + | ^ Bitwise NOT | '' |
+ | === Indirect overloadable operators === | ||
+ | The following operators derive their behavior from the operators above and therefore can be overloaded by implementing functions from above. They can not be overloaded on their own: | ||
- | '' | + | | ^ Operator |
+ | ^ Negative value | '' | ||
+ | ^ Positive value | '' | ||
+ | ^ Shorthand assignment | '' | ||
+ | ^ Increment | '' | ||
+ | ^ Decrement | '' | ||
- | The shorthand assignment | + | === Operators that can not be overloaded === |
- | + | The following | |
- | The same applies for increment/ | + | | ^ Operator |
+ | | Comparision operators | ''<'' | ||
+ | | Assignment operator | ||
+ | | Logic operators | ||
+ | | Object operators | ||
+ | | Null concealing operator | ''??'' | ||
+ | | Tenary operator | ||
+ | | Error control operator | '' | ||
+ | | Object access operator | '' | ||
==== Evaluation order ==== | ==== Evaluation order ==== | ||
Line 86: | Line 106: | ||
$test = $a + $b; | $test = $a + $b; | ||
//First ClassA:: | //First ClassA:: | ||
- | //If not possible ClassB:: | + | //If not possible |
</ | </ | ||
An operand handler can signal that it does not support the given types by returning the const '' | An operand handler can signal that it does not support the given types by returning the const '' | ||
- | |||
- | If the operator handler function declares typehints (e.g. '' | ||
- | |||
- | Both methods can be combined. | ||
==== Error handling ==== | ==== Error handling ==== | ||
- | If an operator is used with an object that does not overload this operator, an NOTICE is triggered, which gives the user a hint about the method that has to be overloaded. For backward compatibility objects, which do not overload the operator, are converted to integer 1 (current behavior). | + | If an operator is used with an object that does not overload this operator, an NOTICE is triggered |
If the class overloads the operator, and the magic method do not return a value, an ERROR is triggered. | If the class overloads the operator, and the magic method do not return a value, an ERROR is triggered. | ||
If the given operand types are not supported on both objects, an ERROR is thrown. | If the given operand types are not supported on both objects, an ERROR is thrown. | ||
+ | |||
+ | If the operator handler declares argument type hints or arguments should be passed-by-reference an ERROR is thrown. | ||
==== Other ==== | ==== Other ==== | ||
A user who overloads an operator MUST ensure, that the magic function do not change the existing operand objects, or it will cause undesirable behavior. At the moment there is no way to enforce immutability on objects, so the user is responsible. The documentation should include a warning about this. | A user who overloads an operator MUST ensure, that the magic function do not change the existing operand objects, or it will cause undesirable behavior. At the moment there is no way to enforce immutability on objects, so the user is responsible. The documentation should include a warning about this. | ||
- | |||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 137: | Line 154: | ||
==== Immutable types ==== | ==== Immutable types ==== | ||
- | To ensure that objects can not be changed (which could cause undesirable behavior), immutable objects (see this [rfc: | + | To ensure that objects can not be changed (which could cause undesirable behavior), immutable objects (see this [[rfc: |
+ | |||
+ | ==== Allow overloading of shorthand assignment operators and increment/ | ||
+ | At moment the engine interprets the assignment and increment/ | ||
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | Accept the existing proposed changes for 8.0: yes/no | + | Add userspace operator overloading as described: yes/no |
+ | |||
+ | ===== Vote ===== | ||
+ | Voting started 2020-03-23 and ends 2020-04-06. | ||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | Draft implementation | + | Implementation |
===== References ===== | ===== References ===== | ||
Line 149: | Line 176: | ||
* [[https:// | * [[https:// | ||
* [[rfc: | * [[rfc: | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
- | ===== Rejected Features | + | ===== Rejectected features |
+ | * Use interfaces instead of magic methods | ||
+ | * Use type hints to declare supported types (this would introduce some special kind of function overloading) | ||
===== Changelog ===== | ===== Changelog ===== | ||
Line 156: | Line 187: | ||
* **0.2:** Allow to signal that the operator handler can not handle the given types by returning '' | * **0.2:** Allow to signal that the operator handler can not handle the given types by returning '' | ||
* **0.3:** Do not catch TypeErrors as they can be thrown in users code (signature checking is done separately from method calling). | * **0.3:** Do not catch TypeErrors as they can be thrown in users code (signature checking is done separately from method calling). | ||
+ | * **0.3.1** Renamed shift handler to '' | ||
+ | * **0.3.2** Renamed some functions handler. Added tables which operators can be overloaded indirectly and which can not be overloaded at all. | ||
+ | * **0.4** Removed type support decisions based on typehints, because this introduces some kind of function overloading. | ||
+ | * **0.5** Disallow argument typehints in operator handlers. |
rfc/userspace_operator_overloading.txt · Last modified: 2020/04/06 19:31 by jbtronics