Re: [Proposal] Struct Data Types
| From: | Benjamin Eberlei | Date: | Fri, 15 Mar 2019 13:19:07 +0000 |
| Subject: | Re: [Proposal] Struct Data Types | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-104742@lists.php.net to get a copy of this message | ||
On Fri, Mar 15, 2019 at 10:54 AM Nikita Popov <nikita.ppv@gmail.com> wrote:
> On Fri, Mar 15, 2019 at 4:49 AM Kenneth Ellis McCall <xellisx@gmail.com>
> wrote:
>
> > Hey all,
> >
> > I'm looking to get feedback on a RFC I want to propose.
> >
> > PHP RFC: Addition of the 'struct' data type.
> >
> > Introduction:
> > PHP has many data types, but does not offer something that is the
> > equivalent to the C struct data type.
> >
> > The purpose of this RFC is to propose a data type of 'struct', which
> > would be a strictly typed, immutable data structure that resembles a mix
> > of a class and an array.
> >
> > Pros:
> > Provides a data type which would immutable and self-validating by
> > mandatory type hinting.
> >
> > Cons:
> > ?
> >
> > Possible future considerations:
> > Advanced Type Validators.
> >
> > Use cases:
> > Configurations, DTOs, anything that needs a strict schema.
> >
> > Proposed usage / syntax:
> > struct MyStuct
> > {
> > boolean|bool 'prop01';
> > integer|int 'prop02';
> > double 'prop03';
> > string 'prop04';
> > array 'prop05';
> > object 'prop06';
> > resource 'prop07';
> > callable 'prop08';
> > iterable 'prop09';
> > Acme\MyClass 'prop10';
> > Acme\ConfStruct 'prop11';
> > array Acme\AnotherStruct 'prop12';
> > ?boolean|bool 'prop13';
> > ?integer|int 'prop14';
> > ?double 'prop15';
> > ?string 'prop16';
> > ?array 'prop17';
> > ?object 'prop18';
> > ?resource 'prop19';
> > ?callable 'prop20';
> > ?iterable 'prop21';
> > ?Acme\MyClass 'prop22';
> > ?Acme\ConfStruct 'prop23';
> > ?array Acme\AnotherStruct 'prop24';
> > }
> > OR?
> >
> > struct MyStuct
> > {
> > 'prop01': boolean|bool;
> > 'prop02': integer|int;
> > 'prop03': float;
> > 'prop04': string;
> > 'prop05': array;
> > 'prop06': object;
> > 'prop07': resource;
> > 'prop08': callable;
> > 'prop09': iterable;
> > 'prop10': Acme\MyClass;
> > 'prop11': Acme\ConfStruct;
> > 'prop12': array Acme\AnotherStruct;
> > 'prop13': ?boolean|bool;
> > 'prop14': ?integer|int;
> > 'prop15': ?float;
> > 'prop16': ?string;
> > 'prop17': ?array;
> > 'prop18': ?object;
> > 'prop19': ?resource;
> > 'prop20': ?callable;
> > 'prop21': ?iterable;
> > 'prop22': ?Acme\MyClass;
> > 'prop23': ?Acme\ConfStruct;
> > 'prop24': ?array Acme\AnotherStruct;
> > }
> >
> > struct Acme\ConfStruct
> > {
> > string 'host';
> > ?int 'port';
> > }
> >
> > struct Acme\AnotherStruct
> > {
> > string 'firstName';
> > string 'lastName';
> > ?integer 'age';
> > }
> >
> > Acme\ConfStruct $a = {
> > 'host' => '127.0.0.1',
> > 'port' => 8088
> > }
> >
> > Acme\MyStruct $myStruct = {
> > 'prop01' => true,
> > 'prop02' => 1,
> > 'prop03' => 1.01,
> > 'prop04' => 'Hello',
> > 'prop05' => ['a', 'b', 'c'],
> > 'prop06' => new stdClass(),
> > 'prop07' => fopen('xyz.txt', 'wb'),
> > 'prop08' => function() {
> > return 1 + 1;
> > },
> > 'prop09' => [
> > [1, 2, 3],
> > [4, 5, 6],
> > [7, 8, 9]
> > ],
> > 'prop10' => new Acme\MyClass,
> > 'prop11' => $a,
> > 'prop12' => [
> > Acme\AnotherStruct [
> > 'firstName' => 'Bob',
> > 'lastName' => 'Walker'
> > ],
> > Acme\AnotherStruct [
> > 'firstName' => 'Little',
> > 'lastName' => 'Johnny',
> > 'age' => 5
> > ],
> > ],
> > 'prop13' => null,
> > 'prop14' => null,
> > 'prop15' => null,
> > 'prop16' => null,
> > 'prop17' => null,
> > 'prop18' => null,
> > 'prop19' => null,
> > 'prop20' => null,
> > 'prop21' => null,
> > 'prop22' => null,
> > 'prop23' => null,
> > 'prop24' => null
> > };
> >
> > $x = new Some\Other\Class($myStruct);
> >
> > echo $myStruct['prop02'];
> > OR?
> >
> > echo $myStruct->prop02;
> > Warning / Errors / Exceptions:
> > Acme\MyStruct $a = {
> > 'prop01' => 5,
> > ...
> > }
> > // Should: throw new TypeError("'prop01' should be set as a boolean
> > type, integer type was attempted.")
> >
> > echo $a['xyz']; // or echo $a->xyz (which ever is the preferred syntax
> > after comments).
> > // Should: trigger_error("<b>Notice</b>: Undefined property:
> > Acme\MyStruct::xyz");
> >
> >
> > https://github.com/ellisgl/PHP-RFC-Struct-Data-Type
> >
>
> I think this a worthwhile topic to pursue -- immutable value objects are
> certainly seeing increased use, and it would be great to increase support
> for them. What I mainly wonder in regard to this RFC is: Do we really need
> a new struct type with a new syntax, or can we get this as a combination of
> multiple features for existing class types? In particular, I think your
> struct type proposal can be split into these three parts:
>
I guess needing a new datatype depends if the struct should be passed by
value instead of by reference.
> 1. Property types. As of PHP 7.4 these are already available, yay! Your
> example also make use of some types (e.g. union types) that are not
> currently supported, but likely will be in the future.
>
> 2. Readonly properties: Without requiring an entire object to be immutable,
> we can add support for readonly properties. This may be either a standalone
> feature, or part of / based on a more general property accessors proposal.
>
Read Only types would be a good idea, DOM already uses readonly as a pseudo
keyword to describe their custom property handlers.
A lot of internal classes could benefit from exposing this explicitly.
> 3. Object construction syntax: The last part is a syntax to construct
> objects without a constructor, using a syntax where property names are
> specified, and which ensures that all non-default properties are
> initialized.
>
> Your example
>
> // declaration
> struct AnotherStruct
> {
> string 'firstName';
> string 'lastName';
> ?int 'age';
> }
> // initialization
> AnotherStruct [
> 'firstName' => 'Little',
> 'lastName' => 'Johnny',
> 'age' => 5
> ]
>
> could then become something like
>
> // declaration
> class AnotherStruct {
> readonly string $firstName;
> readonly string $lastName;
> readonly ?int $age = null;
> }
> // initialization (syntax up to bikeshedding)
> new AnotherStruct {
> $firstName => 'Little',
> $lastName => 'Johnny',
> $age => 5,
> }
>
> I'd generally prefer a solution that is based on the existing class system.
> Especially as it means that other use-cases can also benefit: Sometimes you
> might only want some of your properties to be readonly, etc.
>
> Nikita
>