PHP RFC: Operator Overloading
- Version: 0.1
- Date: 2016-01-02
- Author: Patricio Tarantino patriciotarantino@gmail.com (with Sara Golemon pollita@php.net)
- Status: Draft
- First Published at: http://wiki.php.net/rfc/operator-overloading
Introduction
This RFC adds the possiblity of overloading operators, which allows operators to act according to the type of data they are using. We could define our classes to behave and react to these operators in a custom way. It aims to extend the already extant builtin object overloading used by GMP to userspace classes.
Motivation
Let's say we want to create a custom class to represent imaginary numbers, which could be an array of two Integers. Let's have $a and $b, of type Complex. If we want to add them, or multiply them, we would have to use a custom function. However, it would be nice if we could overload + and * operators for this type, and just use $a + $b or $a * $b.
class Complex { public $real; public $imaginary; public function __construct($real = 0, $imaginary = 0) { $this->real = $real; $this->imaginary = $imaginary; } public function __add($rhs) { $ret = clone $this; if ($rhs instanceof Complex) { $ret->real += $rhs->real; $ret->imaginary += $rhs->imaginary; } else { $ret->real += (int)$rhs; } return $ret; } public function __mul($rhs) { if ($rhs instanceof Complex) { return new Complex(($this->real * $rhs->real) - ($this->imaginary * $rhs->imaginary), ($this->real * $rhs->imaginary) + ($this->imaginary * $rhs->real)); } else { $ret = clone $this; $ret->real *= (int)$rhs; $ret->imaginary *= (int)$rhs; return $ret; } } }
Proposal
Add the following magical functions, available for every class.
public function __add($__value__); // Overloads + operator public function __sub($__value__); // Overloads - operator public function __mul($__value__); // Overloads * operator public function __div($__value__); // Overloads / operator public function __pow($__value__); // Overloads ** operator public function __concat($__value__); // Overloads . operator
Opcache
The implementation of this RFC would add new zend_function pointers to user-defined zend_class_entry structures which opcaches would need to set upon rematerializations.
Proposed PHP Version(s)
7.1
Associativity
When both operands to a binary expression implement operator overloading, the left-hand operand's handler will be invoked. If only one of the two implement overloading, then that side is invoked with the relative operation inverted as necessary. For example (4 < $complex) would invoke the is_greater handler for the $complex object passing in 4 as though it were the RHS expression.
Open questions for discussion
Introduce interface(s) (a la ArrayAccess)?
Proposed Voting Choices
Implement user-space operator overloading as described. Requires 2/3 majority.
Future Expansion
Introduce dispatch for additional operations?
public function __mod($__value__); // Overloads % operator public function __sl($__value__); // Overloads << operator public function __sr($__value__); // Overloads >> operator public function __or($__value__); // Overloads | operator public function __and($__value__); // Overloads & public function __xor($__value__); // Overloads ^ public function __is_identical($__value__); // Overloads === public function __is_not_identical($__value__); // Overloads !== public function __is_equal($__value__); // Overloads == public function __is_not_equal($__value__); // Overloads != public function __is_lesser($__value__); // Overloads < public function __is_lesser_or_equal($__value__); // Overloads <= public function __is_greater($__value__); // Overloads > public function __is_greater_or_equal($__value__); // Overloads >= public function __assign_add($__value__); // Overloads += public function __assign_sub($__value__); // Overloads -= public function __assign_mul($__value__); // Overloads *= public function __assign_div($__value__); // Overloads /= public function __assign_mod($__value__); // Overloads %= public function __assign_sl($__value__); // Overloads <= public function __assign_sr($__value__); // Overloads >>= public function __assign_concat($__value__); // Overloads .= public function __assign_or($__value__); // Overloads |= public function __assign_and($__value__); // Overloads &= public function __assign_xor($__value__); // Overloads ^= public function __assign_pos($__value__); // Overloads **= public function __pre_inc(); // Overloads ++$value public function __pre_dec(); // Overloads --$value public function __post_inc(); // Overloads $value++ public function __post_dec(); // Overloads $value--
Limiting Issue: Greater/Lesser are not distinct
Greater-than, and Greater-than-or-equal expressions are currently implemented by the compiler as inverted Less-than, and Less-than-or-equal expressions. The implementation of this RFC would need to either exclude the is_greater* functions, or it would need to implement is_greater in the runtime as a distinct expression from is_smaller.
References
https://github.com/php/pecl-php-operator exists as an extension based approach to operator overloading. A formal in-tree implementation would merit a new implementation in std_object_handlers.