Take the State of PHP 2026 Survey →

Compact Object Property Assignment View as Markdown

Declined
Authors
Jakob Givoni jakob@givoni.dk
Date
2020-03-17
Version
1.3
Source
wiki.php.net/rfc/compact-object-property-assignment

Votes

Would you like to add support for COPA? closed
Yes
2
No
48
50 voters
ajf No 2020-04-01 15:33
alcaeus No 2020-04-02 08:41
asgrim No 2020-03-31 06:14
ashnazg No 2020-04-01 16:33
beberlei No 2020-03-31 07:38
bishop No 2020-04-01 20:28
bmajdak Yes 2020-03-31 02:30
bukka No 2020-04-05 19:54
carusogabriel No 2020-04-09 12:15
cschneid No 2020-04-08 14:18
danack No 2020-03-31 02:42
davey No 2020-04-01 04:05
dragoonis No 2020-04-06 04:28
duncan3dc No 2020-03-31 15:47
ekin No 2020-04-06 13:12
galvao No 2020-04-06 00:27
gasolwu No 2020-04-01 15:39
geekcom No 2020-04-13 14:15
girgias No 2020-03-31 13:09
googleguy Yes 2020-04-01 05:15
gooh No 2020-03-31 06:38
heiglandreas No 2020-04-05 14:14
jasny No 2020-04-02 01:53
jhdxr No 2020-04-01 16:09
kalle No 2020-03-31 13:02
kguest No 2020-04-02 14:14
klaussilveira No 2020-04-03 18:37
kocsismate No 2020-03-31 07:49
krakjoe No 2020-04-01 07:53
lcobucci No 2020-03-31 06:56
levim No 2020-03-31 02:37
marandall No 2020-03-31 14:53
mariano No 2020-03-31 15:15
mbeccati No 2020-04-01 13:59
nicolasgrekas No 2020-04-07 16:18
nikic No 2020-03-31 07:31
ocramius No 2020-03-31 12:33
peehaa No 2020-03-31 20:44
pollita No 2020-03-31 14:02
ralphschindler No 2020-04-01 01:32
ramsey No 2020-03-31 14:32
rasmus No 2020-04-05 05:28
royopa No 2020-04-13 14:09
salathe No 2020-03-31 07:19
sebastian No 2020-04-02 05:51
sergey No 2020-04-01 08:05
stas No 2020-03-31 17:06
svpernova09 No 2020-04-03 20:35
yunosh No 2020-04-01 07:19
zimt No 2020-04-03 06:35
If you voted no, what was the main reason? closed
I voted yes!
0
I don’t find the feature useful
25
I don’t like the syntax
3
I prefer a more comprehensive solution to this problem
6
I prefer a narrower solution to this problem
0
This breaks backwards compatibility
0
This will have negative implications for future language evolution
0
This will be a nightmare to implement and maintain
0
I prefer not to say
1
35 voters
ajf I don’t like the syntax 2020-04-01 15:33
asgrim I don’t find the feature useful 2020-03-31 06:14
ashnazg I don’t find the feature useful 2020-04-01 16:33
bishop I prefer a more comprehensive solution to this problem 2020-04-01 20:28
bukka I don’t find the feature useful 2020-04-05 19:54
carusogabriel I don’t find the feature useful 2020-04-09 12:15
davey I prefer not to say 2020-04-01 04:06
derick I prefer a more comprehensive solution to this problem 2020-04-01 09:45
dragoonis I don’t find the feature useful 2020-04-06 04:28
duncan3dc I don’t find the feature useful 2020-03-31 15:47
ekin I prefer a more comprehensive solution to this problem 2020-04-06 13:12
galvao I don’t find the feature useful 2020-04-06 00:27
gasolwu I prefer a more comprehensive solution to this problem 2020-04-01 15:39
geekcom I don’t find the feature useful 2020-04-13 14:15
girgias I prefer a more comprehensive solution to this problem 2020-03-31 14:15
gooh I don’t find the feature useful 2020-03-31 06:38
heiglandreas I don’t find the feature useful 2020-04-05 14:14
kguest I don’t find the feature useful 2020-04-02 14:15
klaussilveira I don’t find the feature useful 2020-04-03 18:37
kocsismate I don’t find the feature useful 2020-03-31 07:49
lcobucci I don’t find the feature useful 2020-04-07 08:48
marandall I don’t find the feature useful 2020-03-31 14:53
mariano I don’t find the feature useful 2020-03-31 15:16
mbeccati I don’t like the syntax 2020-04-01 13:59
nikic I prefer a more comprehensive solution to this problem 2020-04-03 20:19
ocramius I don’t find the feature useful 2020-03-31 12:34
pollita I don’t like the syntax 2020-03-31 14:03
ramsey I don’t find the feature useful 2020-03-31 14:33
royopa I don’t find the feature useful 2020-04-13 14:09
sebastian I don’t find the feature useful 2020-04-02 05:51
sergey I don’t find the feature useful 2020-04-01 08:05
stas I don’t find the feature useful 2020-03-31 17:06
svpernova09 I don’t find the feature useful 2020-04-03 20:35
yunosh I don’t find the feature useful 2020-04-01 07:20
zimt I don’t find the feature useful 2020-04-03 06:36
If you did not like the proposed syntax, which alternative would you prefer? closed
A (the proposed one)
0
B
1
C
0
D
0
E
0
F
0
Irrelevant
29
30 voters
ajf Irrelevant 2020-04-01 15:34
asgrim Irrelevant 2020-03-31 06:14
ashnazg Irrelevant 2020-04-01 16:33
bishop B 2020-04-01 20:33
bukka Irrelevant 2020-04-05 19:54
carusogabriel Irrelevant 2020-04-09 12:15
cschneid Irrelevant 2020-04-08 14:19
davey Irrelevant 2020-04-01 04:05
dragoonis Irrelevant 2020-04-06 04:28
duncan3dc Irrelevant 2020-03-31 15:49
galvao Irrelevant 2020-04-06 00:29
gasolwu Irrelevant 2020-04-01 15:37
geekcom Irrelevant 2020-04-13 14:16
girgias Irrelevant 2020-03-31 14:14
gooh Irrelevant 2020-03-31 06:38
heiglandreas Irrelevant 2020-04-05 14:15
kguest Irrelevant 2020-04-02 14:18
klaussilveira Irrelevant 2020-04-03 18:37
kocsismate Irrelevant 2020-03-31 07:49
lcobucci Irrelevant 2020-04-07 08:49
marandall Irrelevant 2020-03-31 14:53
mariano Irrelevant 2020-03-31 15:16
ocramius Irrelevant 2020-03-31 12:34
ramsey Irrelevant 2020-03-31 15:11
rasmus Irrelevant 2020-04-05 05:28
sebastian Irrelevant 2020-04-02 05:52
sergey Irrelevant 2020-04-01 08:06
stas Irrelevant 2020-03-31 17:06
svpernova09 Irrelevant 2020-04-03 20:35
zimt Irrelevant 2020-04-02 08:28

Discussions on the mailing list

[RFC] [DISCUSSION] Compact Object Property Assignment
by Jakob Givoni · 45 messages
[VOTE] Compact Object Property Assignment
by Jakob Givoni · 10 messages
Multiple property assigning without constructor
by Taras Chornyi · 3 messages

RFC text

Copied from wiki.php.net, last synchronized Oct 13, 2026 11:52 UTC

COPA: A pragmatic approach to object literals

Introduction

Summary

This RFC proposes a new, compact syntax to assign values to multiple properties on an object in a single expression.

This pseudo object literal notation, (though not limited to such use) is intended to enable the developer to create an object and populating it inline, f.ex. directly as an argument in a function call.

As an alternative to writing a data structure as an associative array, COPA gives the data a documented signature so that you know what parameters are expected and their value types.

COPA does not introduce any new concepts or complexities, but merely a new syntax aimed at making millions of PHP developers write their code in a simpler way. The code becomes easier to write and read and thus more maintainable without any lateral limitations or factual downsides.

Example

Let’s start with an example that demonstrates the essence of COPA.

Instead of doing this...

$myObj->a = 1;
$myObj->b = 2;
$myObj->c = 3;

You will be able to do this:

$myObj->[
    a = 1,
    b = 2,
    c = 3,
];

COPA is everything that comes after the object expression. You can use COPA on any expression that evaluates to an object. COPA is not tied to object construction, but can be used anytime, anywhere in the objects life, as many times as you want.

See more use cases below.

Motivation

The purpose of this feature is to lighten the effort of creating, populating and sending data structures, from small to large ones.

The goal was to find a solution that meets the following criteria:

  • Brief - only mention the object once (less repetition)
  • Inline - object can be created and populated in a single expression (pseudo object literals, nested objects)
  • Typo-proof - property names can be autocompleted easily by IDE (faster typing, fewer errors)
  • Type-checking - IDE can verify correct type for typed properties and annotated virtual properties
  • Order-agnostic - properties can be specified in any order (though note that the order may change the result!)
  • Sparcity - any property can be “skipped” (“skipped” properties may acquire a default value)
  • Simple - does what you would expect without introducing any new concepts into the language

My focus is to find a pragmatic solution that is trivial to implement, and won’t impede futher development of the language.

If you have ever wanted to create, populate and send an object inside a function call, COPA is for you!

Proposal

Syntax

The proposed syntax consists of the object arrow operator followed by a set of square brackets containing a comma-separated list of assignments in the form of property name equals expression:

<object-expression> -> [
    `<property-name> = <expression>`,
    [repeat as needed],
]

A trailing comma is permitted for the same reasons it's permitted in array literals and function calls (as of PHP 7.3).

The whole block is considered an expression that returns the object before the arrow.

This syntax was chosen for its availability in the language. If we land on another syntax, I’m not married to this one. The only criteria are that it doesn’t conflict with anything else, that it is trivial to implement, brief and feels ok.

Interpretation

Each comma-separated assignment inside the brackets is executed as an assignment of the named property on the object preceding the block. If the property is defined and publicly accessible, it will simply be set, or possible throw a TypeError. If there's no property with that name, or if it's protected or private, the magic method __set will be called just like you would expect. When used in an expression, COPA simply returns the object itself.

If you replace COPA with single line assignments, you will always get the same result, f.ex.:

$foo->[
    a = 1,
    b = myfunc(),
    c = $foo->bar(),
];
 
// The COPA above is identical to
$foo->a = 1;
$foo->b = myfunc();
$foo->c = $foo->bar();

Use cases

Create and send struct

// Instead of this:
 
$myObj = new Foo; // 1. Create struct-like object without constructor arguments
 
$myObj->a = 1; // 2. Populate public properties
$myObj->b = 2;
$myObj->c = 3;
 
doTheFoo($myObj); // 3. Send or process
 
// Use COPA:
 
doTheFoo((new Foo)->[
    a = 1,
    b = 2,
    c = 3,
]);

No boilerplate needed.

Stop using arrays

// Instead of this:
 
doSomething([
    'a' => 1, // Anonymous array doesn't provide any help on parameter names
    'b' => 2, // or types
]);
 
// Use COPA:
 
class Options { // Give the data a signature, a well-defined structure
    public $a;
    public $b;
}
 
doSomething((new Options)->[
    a = 1, // Parameter name and type checking
    b = 2,
]);

If you often create, populate and send the same families of data structure, declaring those structures and using COPA makes it a breeze.

Nested COPA

COPA is not limited to a flat structure.

(new Foo)->[
    om = 'get',
    mane = 'a',
    hum = (new Foo)->[
        mane = 'life',
    ],
];

Split options from services

Separate concerns and use composition. In this example, once you have instantiated Foo, the options are no longer writeable, even though the options were public properties.

class FooOptions {
    public ?string $mane = null;
    public int $padme = 1; // Optional, with default
    public ?string $hum = null;
}
 
class Foo {
    protected FooOptions $options;
 
    public function __construct(FooOptions $options) {
        // Do some validate here if you must, f.ex. checking for mandatory parameters
        $this->options = clone $options;
    }
}
 
$myFoo = new Foo((new FooOptions)->[
    mane = 'get',
    hum = 'life',
]);

If you can’t wait for “named parameters” and often resort to “parameter bags” this is a perfectly valid and saner alternative.

Special cases

Clarification of edge-case behavior.

Execution order

The fact that the assignments are executed in the order they are listed (just as if they had been specified on separate lines), has the following consequence:

$myObj->[
    foo = 10,
    bar = $myObj->foo + 20,
];
 
var_dump($myObj->bar); // int(30)

As the assignments are carried out in order on the object, you can use the new value of a previous assigment in a following one.

Exceptions

If an expression inside a COPA block throws an exception, the result is the same as if the assignments had been done the old way, f.ex. if we have:

class Foo {
    public $a;
    public $b;
    public $c;
}
 
$foo = new Foo();
 
function iThrow() {
    throw new \Exception();
}

Then the following examples behave identically:

// With COPA:
 
try {
    $foo->[
        a = 'a',
        b = iThrow(),
        c = 'c',
    ];
} catch (\Throwable $e) {
    var_dump($foo);
}
// Without COPA:
 
try {
    $foo->setA('a')
        ->setB(iThrow())
        ->setC('c');
} catch (\Throwable $e) {
    var_dump($foo);
}
 
// OR
 
try {
    $foo->a = 'a';
    $foo->b = iThrow();
    $foo->c = 'c';
} catch (\Throwable $e) {
    var_dump($foo);
}

The result in all cases is that a will be set, while b and c will not:

object(Foo)#1 (3) {
  ["a"]=>
  string(1) "a"
  ["b"]=>
  NULL
  ["c"]=>
  NULL
}

COPA is not an atomic operation in the same way that method chaining isn’t.

Out of scope / future scope

This section contains features that is not considered for implementation in version 1 of COPA but may be considered later.

You can’t do that

The following examples show various things that are currently possible when using regular property accessor, though they won’t work inside a COPA block:

$p = 'foo';
$myObj->$p = 'bar'; // Variable property name
$a->{"fo" . "o"} = 'baz'; // Property name generated from expression
$a->b->c = 'hum'; // Creating default object from empty value
$a->d['e'] = 'dear'; // Setting array element inside property
$a->f++; // Increment/decrement of property value
 
$myObj->[
    $p = 'bar', // Syntax error
    {"foo"} = 'bar', // Syntax error
    b->c = 'hum', // Syntax error - but see Nested COPA below...
    d['e'] = 'dear', // Syntax
    f++, // Syntax error
];

These can be implemented in the future if there is a demand.

Nested COPA on existing objects

The following syntax could be supported in the future:

// This example, using current syntax...
 
$foo->a = 1;
$foo->b->c = 2;
 
// Could be written with COPA like this:
 
$foo->[
    a = 1,
    b->[
        c = 2,
    ],
];
 
// But for now you'll have to do this:
 
$foo->[
    a = 1,
    b = $foo->b->[
        c = 2,
    ],
];

Backward Incompatible Changes

None.

Note! Array followed by square bracket causes syntax error in PHP 7.4. This new syntax is optional. If you don't use it, your code will continue to run.

Proposed PHP Version(s)

PHP 8.0

Open Issues

Alternative syntaxes

I’m going to suggest some alternative syntaxes, which we can vote on, provided their feasibility has been vetted by an experienced internals developer:

Syntax A

This is the originally proposed one:

$foo->[
    a = 1,
    b = 2,
    c = (new Foo)->[
        a = 3,
        b = 4,
    ],
];

Syntax B

Since the deprecation of curly brackets as array access in PHP 7.4, that notation could be used to assign properties:

$foo{
    a = 1,
    b = 2,
    c = (new Foo){
        a = 3,
        b = 4,
    },
};

Going from deprecation in 7.4 to removal of support in 8.0 may is not unprecedented. Old code that has not been mended won’t silently do something spurious.

Syntax C

No wrapper:

$foo->
    a = 1,
    b = 2,
    c = (new Foo)->
        a = 3,
        b = 4,
    ;,
;

Nesting becomes awkward - how do we jump out again?

Note! This looks more like a chain of normal assignments, but that can be confusion since those normally return the value assigned, not the object itself.

Syntax D

Repeating the arrow for familiarity with regular property assignment:

$foo
    ->a = 1,
    ->b = 2,
    ->c = (new Foo)
        ->a = 3,
        ->b = 4,
    ;,
;

Same issues as previous.

Syntax E

Like the original but with normal brackets instead of square ones:

$foo->(
    a = 1,
    b = 2,
    c = (new Foo)->(
        a = 3,
        b = 4,
    ),
);

Syntax F

WITH syntax

myObj.with {
     foo = 10
     bar = foo + 20
}

If this is the preferred syntax it will require a new RFC.

Rejected Features

Some suggested features have been rejected due to the fact that COPA aims to be pragmatic, with a trivial implementation and without introducing any new concepts to avoid a combinatorial explosion of complexities in the future.

Mandatory properties

Some have voiced criticism that COPA is of little use without also enforcing mandatory properties to be set.

Rowan Tommins:

It seems pretty rare that an object would have no mandatory properties, so saying “if you have a mandatory property, COPA is not for you” is ruling out a lot of uses.

Michał Brzuchalski:

This helps to avoid bugs where a property is added to the class but forgot to be assigned it a value in all cases where the class is instantiated and initialized

Mandatory properties are typed properties without a default value. They are in the uninitialized state until they are assigned a value. It has been suggested that an exception should be thrown at the end of the constructor if any property is still uninitialized, but this idea has not yet caught on. COPA doesn’t have any obvious way of enforcing mandatory properties.

COPA won’t support this since COPA doesn’t introduce any new concepts or complexities. The lack of this feature is not a limitation of COPA when compared to current functionality.

For now you must continue to write your own validation code to be carried out at the appropriate “point of no return”.

Atomic operations

It’s also been suggested that assigning multiple values using COPA should be an atomic operation that either succeeds or fails in its entirety (i.e. like a “transaction”).

Though that sounds cool, this is an edge case that won’t have any significant impact. If you were planning to resume gracefully with an incomplete object you should probably reconsider your goals in life.

Note! Chaining method calls is not an atomic operation either. The cost/benefit of implementing “transaction” and “rollback” behavior is negative.

Vote

Voting starts 2020-03-31 and ends 2020-04-13.

The primary vote of whether or not to accept this RFC requires a 2/3 majority.

Vote: Would you like to add support for COPA? — Yes: 2 · No: 48 (closed)

Vote: If you voted no, what was the main reason? — I voted yes!: 0 · I don’t find the feature useful: 25 · I don’t like the syntax: 3 · I prefer a more comprehensive solution to this problem: 6 · I prefer a narrower solution to this problem: 0 · This breaks backwards compatibility: 0 · This will have negative implications for future language evolution: 0 · This will be a nightmare to implement and maintain: 0 · I prefer not to say: 1 (closed)

Vote: If you did not like the proposed syntax, which alternative would you prefer? — A (the proposed one): 0 · B: 1 · C: 0 · D: 0 · E: 0 · F: 0 · Irrelevant: 29 (closed)

Patches and Tests

There are yet no patches nor tests. The question of who will be developing this will be addressed if the RFC passes.

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature
  4. a link to the language specification section (if any)

References

Related RFCs: