====== 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 =====