====== PHP RFC: __toArray() ====== * Version: 1.1 * Date: 2019-08-28 * Author: Steven Wade, stevenwadejr@gmail.com * Status: Under Discussion * First Published at: http://wiki.php.net/rfc/to-array ===== Introduction ===== This RFC proposes to add a new magic method called __toArray() to allow a class to control how it is represented when converted to an array. PHP contains many [[https://www.php.net/manual/en/language.oop5.magic.php|magic methods]] that give a class greater control over its interaction with the language. The methods [[https://wiki.php.net/rfc/custom_object_serialization|__serialize() and __unserialize()]] give a class control over how it is serialized, __clone() allows control over how self copies are made, and __toString() allows a class to control how it is represented when converted to a string. Adding a __toArray() method gives developers the ability to transform a class to an array in similar fashion. ===== Proposal ===== Example: class Person { protected $name; protected $email; public $foo = 'bar'; public function __construct(string $name, string $email) { $this->name = $name; $this->email = $email; } public function __toArray() { return [ 'name' => $this->name, 'email' => $this->email, ]; } } $person = new Person('John Doe', 'j.doe@example.com'); Example usage: $personArray = (array) $person; // casting triggers __toArray() ==== What this is ==== The example above shows the method __toArray() used in a type-casting context. This proposal would have objects implementing the __toArray() magic method called within //any// array context including type hinting and return types (only when using weak typing - strong typing will throw an error). Similar to PHP's current implementation of __toString(), a copy of the given object's value as an array is made upon conversion. **Type Hinting** function foo(array $person) { var_dump($person); } // Output /* array(2) { ["name"]=> string(8) "John Doe" ["email"]=> string(17) "j.doe@example.com" } */ **Return Type** function bar(Person $person): array { return $person; } var_dump(bar($person)); // Output /* array(2) { ["name"]=> string(8) "John Doe" ["email"]=> string(17) "j.doe@example.com" } */ **array_* and built-in functions** The array operating functions listed on the [[https://www.php.net/manual/en/ref.array.php|Array Functions]] would first convert an object implementing the __toArray() method before continuing operations. print_r( array_keys($person) ); // Output /* Array ( [0] => first [1] => email ) */ === Strict Types === Automatic casting will not work when using strict types. declare(strict_types=1); function bar(Person $person): array { return $person; } bar($person); // Throws an error: "Return value of bar() must be of the type array, object returned" function foo(array $person) { var_dump($person); } foo($person); // Throws an error: "Argument 1 passed to foo() must be of the type array, object given" Manual casting within strict types will continue to work and is allowed. declare(strict_types=1); function bar(Person $person): array { return (array) $person; } bar($person); // Returns an array function foo(array $person) { var_dump($person); } foo((array) $person); // Allowed ==== What this is not ==== This proposal does not allow accessing and setting values as you would in a normal array, that functionality remains with classes implementing the [[https://www.php.net/manual/en/class.arrayaccess.php|ArrayAccess]] interface. Array functions that operate on an array by reference such as sort or shuffle will not work on an object implementing __toArray() under this proposal. ===== Backward Incompatible Changes ===== None ===== Proposed PHP Version(s) ===== Next PHP version (target 8.0) ===== RFC Impact ===== ==== To SAPIs ==== :?: Help needed ==== To Existing Extensions ==== :?: Help needed ==== To Opcache ==== :?: Help needed ===== Concerns ===== A [[https://externals.io/message/105589#105594|concern raised in the initial RFC proposal discussion]] referred to the existing behavior of casting and exposing object state: >As it currently stands, the array cast is the only operation capable of exposing object state without triggering any kind of access guards: it is very much required for anything that works with reflection and typed properties, and possibly the only operation in PHP that operates on state without some contraption intercepting its execution. As a response to this concern, the new get_mangled_object_vars() function was added in [[https://github.com/php/php-src/commit/eecd8961d94c50cc6cdc94ec80df8c1ce4881a76|PHP 7.4]]. ===== Proposed Voting Choices ===== Vote will require 2/3 majority ===== Patches and Tests ===== No patch exists yet. A [[https://github.com/sgolemon/php-src/tree/experimental.toarray|proof of concept]] for type casting was created by Sara Golemon, but no official patch has been created. Will need help with this. ===== References ===== * PHP Manual: [[https://www.php.net/manual/en/language.oop5.magic.php|magic methods]], [[https://www.php.net/manual/en/ref.array.php|Array Functions]], [[https://www.php.net/manual/en/class.arrayaccess.php|ArrayAccess]] . * PHP RFC: [[https://wiki.php.net/rfc/custom_object_serialization|New custom object serialization mechanism]] . * Initial idea and discussion: [[https://externals.io/message/105589]] . ===== Rejected Features =====