rfc:to-array

PHP RFC: __toArray()

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 magic methods that give a class greater control over its interaction with the language. The methods __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 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 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 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 PHP 7.4.

Proposed Voting Choices

Vote will require 2/3 majority

Patches and Tests

No patch exists yet. A proof of concept for type casting was created by Sara Golemon, but no official patch has been created. Will need help with this.

References

Rejected Features

rfc/to-array.txt · Last modified: 2020/02/11 13:57 by stevenwadejr