rfc:user_defined_operator_overloads
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:user_defined_operator_overloads [2021/12/07 20:29] – Added OperandPosition Enum jordanrl | rfc:user_defined_operator_overloads [2022/01/17 01:16] (current) – closed voting jordanrl | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: User Defined Operator Overloads ====== | ====== PHP RFC: User Defined Operator Overloads ====== | ||
- | * Version: 0.5 | + | * Version: 0.6 |
* Date: 2021-08-14 | * Date: 2021-08-14 | ||
* Author: Jordan LeDoux, jordan.ledoux@gmail.com | * Author: Jordan LeDoux, jordan.ledoux@gmail.com | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
Line 100: | Line 100: | ||
This is avoided by allowing the restrictions on operator names to be separated from the restrictions on function names. | This is avoided by allowing the restrictions on operator names to be separated from the restrictions on function names. | ||
+ | |||
+ | === Callable === | ||
+ | |||
+ | Operand implementations can be called on an instance of an object the way normal methods can. | ||
+ | |||
+ | <code php> | ||
+ | // These all will work normally | ||
+ | $op = ' | ||
+ | $callable = [$obj, ' | ||
+ | |||
+ | // Calls on the object variable | ||
+ | $obj-> | ||
+ | $obj-> | ||
+ | $callable(1, | ||
+ | |||
+ | // Calls using call_user_func | ||
+ | call_user_func([$obj, | ||
+ | call_user_func($callable, | ||
+ | |||
+ | // This will error since + is not static | ||
+ | call_user_func(' | ||
+ | </ | ||
+ | |||
+ | They can be also be directly invoked with a Closure however. This fully supports Reflection, and allows direct calls. | ||
+ | |||
+ | <code php> | ||
+ | // Manually creating a closure allows a direct function call | ||
+ | $closure = Closure:: | ||
+ | $closure(1, OperandPosition:: | ||
+ | |||
+ | // You can also retrieve the closure through Reflection | ||
+ | $closure = (new ReflectionMethod($obj, | ||
+ | $closure(1, OperandPosition:: | ||
+ | |||
+ | $closure = (new ReflectionObject($obj))-> | ||
+ | $closure(1, OperandPosition:: | ||
+ | </ | ||
==== Add InvalidOperatorError ==== | ==== Add InvalidOperatorError ==== | ||
Line 182: | Line 219: | ||
$val1 = $num + 1; | $val1 = $num + 1; | ||
// this is equivalent to | // this is equivalent to | ||
- | // $val1 = $num->' | + | // +(1, OperandPosition:: |
$val2 = 1 + $num; | $val2 = 1 + $num; | ||
// this is equivalent to | // this is equivalent to | ||
- | // $val2 = $num->' | + | // +(1, OperandPosition:: |
</ | </ | ||
Line 230: | Line 267: | ||
| '' | | '' | ||
| ''&'' | | ''&'' | ||
- | | '' | + | | '' |
| '' | | '' | ||
| '' | | '' | ||
Line 327: | Line 364: | ||
Because comparisons have a reflection relationship instead of a commutative one, the $operandPos argument is omitted as it could only be used for evil (making '' | Because comparisons have a reflection relationship instead of a commutative one, the $operandPos argument is omitted as it could only be used for evil (making '' | ||
- | Comparison | + | Equality and comparison |
The signature for the equals operator has the additional restriction of returning '' | The signature for the equals operator has the additional restriction of returning '' | ||
Line 341: | Line 378: | ||
Any return value larger than 0 will be normalized to 1, and any return value smaller than 0 will be normalized to -1. | Any return value larger than 0 will be normalized to 1, and any return value smaller than 0 will be normalized to -1. | ||
- | The $operandPos argument is omitted as it could only be used for evil e.g. implementing different comparison logic depending on which side its on. Instead of passing $operandPos the engine will multiply the result of the call by (-1) where appropriate: | + | The $operandPos argument is omitted as it could only be used for evil e.g. implementing different comparison logic depending on which side it' |
<code php> | <code php> | ||
Line 360: | Line 397: | ||
$obj = new Number(5); | $obj = new Number(5); | ||
- | $less_than = ($obj < 5); | + | $less_than = $obj < 5; |
// is equivalent to | // is equivalent to | ||
- | // $less_than = ($obj->' | + | // (< |
$greater_than = 5 > $obj; | $greater_than = 5 > $obj; | ||
// is equivalent to | // is equivalent to | ||
- | // $greater_than = ( ($obj->' | + | // ( (< |
</ | </ | ||
Line 392: | Line 429: | ||
The '' | The '' | ||
+ | |||
+ | ==== Attributes ==== | ||
+ | |||
+ | A new target '' | ||
+ | |||
+ | ==== Reflection ==== | ||
+ | |||
+ | Several changes to reflection must be made to support this feature. | ||
+ | |||
+ | === Changes To ReflectionClass === | ||
+ | |||
+ | == Changes to getMethods(), | ||
+ | |||
+ | These methods need to be updated to ignore the operator methods. Since these are stored internally like any other function on the class entry, they need to be filtered from the results. | ||
+ | |||
+ | The reason for removing the operators from this result is because the operator methods are not callable with string literals on the object. Since they cannot be called like a method is, they should not be returned with the other methods on a class. | ||
+ | |||
+ | == Adding getOperators(), | ||
+ | |||
+ | These methods must be added to interact with the function handlers for the operator implementations. They will act as an inverse to the changes above. | ||
+ | |||
+ | Operator methods will be represented by an instance of '' | ||
+ | |||
+ | === Changes To ReflectionMethod === | ||
+ | |||
+ | == New Method isOperator() == | ||
+ | |||
+ | Returns true if the method being reflected uses the '' | ||
===== FAQ ===== | ===== FAQ ===== | ||
Line 480: | Line 545: | ||
<code php> | <code php> | ||
- | function processMoneyValues(Money $left, Money $right) | + | class Money { |
- | { | + | operator +(Money $other, OperandPosition |
- | return $left + $right; | + | |
} | } | ||
- | processMoneyValues( | + | $result = new Money(5, ' |
- | | + | |
- | | + | |
- | ); | + | |
// Type error, Vector2d can't be used as Money | // Type error, Vector2d can't be used as Money | ||
</ | </ | ||
- | This can also be caught by typing the arguments to the operator implementations themselves. | + | This can also be caught by typing the arguments to a helper function: |
<code php> | <code php> | ||
- | class Money { | + | function processMoneyValues(Money $left, Money $right) |
- | operator +(Money $other, OperandPosition | + | { |
+ | return $left + $right; | ||
} | } | ||
- | $result = new Money(5, ' | + | processMoneyValues( |
+ | | ||
+ | | ||
+ | ); | ||
// Type error, Vector2d can't be used as Money | // Type error, Vector2d can't be used as Money | ||
Line 583: | Line 648: | ||
// The rest of the extension' | // The rest of the extension' | ||
</ | </ | ||
+ | |||
+ | To further help extensions support this feature, there are two helper functions: | ||
+ | |||
+ | <code c> | ||
+ | int has_overload = zend_std_has_op_overload(opcode, | ||
+ | |||
+ | zend_function overload_method = zend_std_get_op_overload(opcode, | ||
+ | </ | ||
+ | |||
+ | It is safe to pass any zval pointer to '' | ||
==== To Opcache ==== | ==== To Opcache ==== | ||
Line 608: | Line 683: | ||
This RFC deals with allowing each class to define its own interaction with operators. However, if overloading the operator itself were desired for the entire application, | This RFC deals with allowing each class to define its own interaction with operators. However, if overloading the operator itself were desired for the entire application, | ||
- | ===== Proposed Voting Choices | + | ==== Functions for Operators |
- | Add limited user-defined | + | Having functions for operators may be beneficial when objects which use operator overloads are used in conjunction with functions like '' |
+ | |||
+ | <code php> | ||
+ | array_reduce($arrOfObjs, | ||
+ | </ | ||
+ | |||
+ | These could be polyfilled in PHP currently: | ||
+ | |||
+ | <code php> | ||
+ | array_reduce($arrOfObjs, | ||
+ | </ | ||
+ | |||
+ | ==== Query Builder Improvements | ||
+ | With some additional improvements, | ||
+ | |||
+ | <code php> | ||
+ | $qb-> | ||
+ | </code> | ||
+ | |||
+ | ==== Enum Return Type For <=> ==== | ||
+ | |||
+ | Returning an enum for the <=> would be preferable for two reasons. | ||
+ | |||
+ | - It allows the function to return an equivalent of ' | ||
+ | - It is easier | ||
+ | |||
+ | This is listed as future scope because there is a separate RFC which covers this feature: https:// | ||
+ | |||
+ | It is listed as a separate RFC because it is something that could be delivered whether or not this RFC passes. | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 621: | Line 724: | ||
- a link to the language specification section (if any) | - a link to the language specification section (if any) | ||
- | ===== References | + | ===== Proposed Voting Choices |
+ | Add limited user-defined operator overloads as described: yes/no. A 2/3 vote is required to pass. | ||
+ | |||
+ | ===== Vote ===== | ||
+ | |||
+ | Voting started 2022-01-03 at 00:15 UTC and will end 2022-01-17 at 00:15 UTC. | ||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * No | ||
+ | </ | ||
===== Changelog ===== | ===== Changelog ===== |
rfc/user_defined_operator_overloads.1638908998.txt.gz · Last modified: 2021/12/07 20:29 by jordanrl