Hi internals,
In PHP 8.1, it is possible to allow constructing any class name in an initializer, after the approval of https://wiki.php.net/rfc/new_in_initializers
php > static $x1 = new ArrayObject(['key' => 'value']);
php > static $x2 = new stdClass();
php > static $x3 = (object)['key' => 'value'];
Fatal error: Constant expression contains invalid operations in php shell code on line 1
What are your thoughts on allowing the (object)
cast in initializer types where new
was already allowed, but only when followed by an array literal node. (e.g. continue to forbid (object)SOME_CONSTANT
) (see https://wiki.php.net/rfc/new_in_initializers)
stdClass has never implemented a factory method such as __set_state
(which is not yet allowed). Instead, (object)[]
or the (object)array()
shorthand is typically used when a generic object literal is needed. This is also how php represents objects in var_export.
php > var_export(new stdClass());
(object) array(
)
Reasons:
- The ability to construct empty stdClass instances but not non-empty ones is something users would find surprising,
and a lack of support for(object)[]
be even more inconsistent if factory methods were allowed in the future. - stdClass is useful for some developers, e.g. in unit tests, when using libraries requiring it for parameters,
when you need to ensure data is encoded as a JSON{}
rather than[]
, etc. - It would help developers write a clearer api contract for methods,
e.g.function setData(stdClass $default = (object)['key' => 'value'])
is clearer thanfunction setData(?stdClass $default = null) { $default ??= (object)['key' => 'value'];
- stdClass may be the only efficient built-in way to represent objects with arbitrary names if RFCs such as https://externals.io/message/115800
passed
Thanks,
Tyson
Hey Tyson,
What are your thoughts on allowing the
(object)
cast in initializer
types wherenew
was already allowed, but only when followed by an array
literal node. (e.g. continue to forbid(object)SOME_CONSTANT
) (see
https://wiki.php.net/rfc/new_in_initializers)
Right now, there's even an interest in getting rid (or deprecating) dynamic
properties on objects: why push the complete opposite ways?
What is the actual value of using an stdClass instance instead of an
array<string, mixed>
(already supported)?
Hey Marco Pivetta,
What are your thoughts on allowing the
(object)
cast in initializer types wherenew
was already allowed, but only when followed by an array literal node. (e.g. continue to forbid(object)SOME_CONSTANT
) (see https://wiki.php.net/rfc/new_in_initializers)
...
Reasons:
- The ability to construct empty stdClass instances but not non-empty ones is something users would find surprising,
and a lack of support for(object)[]
be even more inconsistent if factory methods were allowed in the future.- stdClass is useful for some developers, e.g. in unit tests, when using libraries requiring it for parameters,
when you need to ensure data is encoded as a JSON{}
rather than[]
, etc.- It would help developers write a clearer api contract for methods,
e.g.function setData(stdClass $default = (object)['key' => 'value'])
is clearer thanfunction setData(?stdClass $default = null) { $default ??= (object)['key' => 'value'];
- stdClass may be the only efficient built-in way to represent objects with arbitrary names if RFCs such as https://externals.io/message/115800 passed
passed
Right now, there's even an interest in getting rid (or deprecating) dynamic properties on objects: why push the complete opposite ways?
What is the actual value of using an stdClass instance instead of an
array<string, mixed>
(already supported)?
My original message had a section with reasons why an end user might want that.
There's a push for getting rid of (or deprecating) dynamic properties on objects that are not stdClass (or subclasses)
Not a push for getting rid of stdClass. Way too many things use stdClass to get rid of stdClass.
(whether or not stdClass gets aliased or even renamed to DynamicObject).
php > var_dump(json_decode('{}'));
object(stdClass)#1 (0) {
}
Thanks,
Tyson
Hey Tyson,
My original message had a section with reasons why an end user might want
that.
Yeh, it sounds like stuff we wanna get away from 😬
Not a push for getting rid of stdClass. Way too many things use stdClass
to get rid of stdClass.
Yes, but for legacy reasons, not for further perpetuating the practice.
Hey Tyson,
My original message had a section with reasons why an end user might want
that.Yeh, it sounds like stuff we wanna get away from 😬
Point of order here: "we" is not unanimous.
-Mike
What are your thoughts on allowing the
(object)
cast in initializer types wherenew
was already allowed
I'm not strongly opposed to this, but am not convinced it's a big
improvement.
Firstly, as with everything involving stdClass, I would be more
interested in a) improving the initialization of anonymous objects, and
b) allowing those in initialisers (the RFC currently forbids them, but
doesn't say why, so I'm not sure if it's an implementation decision or a
philosophical one).
Secondly, if you have enough knowledge of the structure to provide an
inline default, then you probably have enough to be worth defining a
named class, even if that class then implements __set() to allow
additional ad hoc properties. That class can then have its own defaults,
so that your example becomes function setData(Data $values = new Data())
Regards,
--
Rowan Tommins
[IMSoP]
On Sat, Sep 25, 2021 at 10:45 AM tyson andre tysonandre775@hotmail.com
wrote:
In PHP 8.1, it is possible to allow constructing any class name in an
initializer, after the approval of
https://wiki.php.net/rfc/new_in_initializersphp > static $x1 = new ArrayObject(['key' => 'value']); php > static $x2 = new stdClass(); php > static $x3 = (object)['key' => 'value']; Fatal error: Constant expression contains invalid operations in php shell code on line 1
What are your thoughts on allowing the
(object)
cast in initializer
types wherenew
was already allowed, but only when followed by an array
literal node.
I think for consistency's sake, we'd want to provide a base constructor to
stdClass to take an associative array that maps into dynamic properties,
e.g.
class stdClass {
public function __construct(array $props) {
foreach ($prop as $name => $val) {
$this->$name = $val;
}
}
}
Then you could:
php> static $x3 = new stdClass(['key' => 'value']);
This avoids special-casing object cases in the engine while making it clear
that a stdClass is what you wind up with, and honestly I think it'd be a
useful pattern to use when initializing stdClass with defaults elsewhere.
As to whether or not we SHOULD: While using declared props is preferred in
the vast majority of cases, both for performance and for readability, there
are legitimate cases where a short lived container wants the flexibility
and convenience of an untyped, dynamic structure like an associative array
with the visually clean aesthetic of object access. stdClass does that,
and even if deprecation of dynamic properties passes it will continue to do
that. I started this paragraph ambivalent about the feature, but I think I
convinced myself around to a +1, though in the constructor form, not the
cast form.
-Sara
I think for consistency's sake, we'd want to provide a base constructor to
stdClass to take an associative array that maps into dynamic properties,
e.g.class stdClass {
public function __construct(array $props) {
foreach ($prop as $name => $val) {
$this->$name = $val;
}
}
}Then you could:
php> static $x3 = new stdClass(['key' => 'value']);
If the structure of $something = {};
would ever be allowed in PHP, the
following could be done instead: $something = { ...$array };
. This will
reduce the dependency on the stdClass.
On Sat, Sep 25, 2021 at 5:45 PM tyson andre tysonandre775@hotmail.com
wrote:
Hi internals,
In PHP 8.1, it is possible to allow constructing any class name in an
initializer, after the approval of
https://wiki.php.net/rfc/new_in_initializersphp > static $x1 = new ArrayObject(['key' => 'value']); php > static $x2 = new stdClass(); php > static $x3 = (object)['key' => 'value']; Fatal error: Constant expression contains invalid operations in php shell code on line 1
What are your thoughts on allowing the
(object)
cast in initializer
types wherenew
was already allowed, but only when followed by an array
literal node. (e.g. continue to forbid(object)SOME_CONSTANT
) (see
https://wiki.php.net/rfc/new_in_initializers)stdClass has never implemented a factory method such as
__set_state
(which is not yet allowed). Instead,(object)[]
or the(object)array()
shorthand is typically used when a generic object literal is needed. This
is also how php represents objects in var_export.php > var_export(new stdClass()); (object) array( )
Reasons:
- The ability to construct empty stdClass instances but not non-empty ones
is something users would find surprising,
and a lack of support for(object)[]
be even more inconsistent if
factory methods were allowed in the future.- stdClass is useful for some developers, e.g. in unit tests, when using
libraries requiring it for parameters,
when you need to ensure data is encoded as a JSON{}
rather than[]
,
etc.- It would help developers write a clearer api contract for methods,
e.g.function setData(stdClass $default = (object)['key' => 'value'])
is clearer thanfunction setData(?stdClass $default = null) { $default ??= (object)['key' => 'value'];
- stdClass may be the only efficient built-in way to represent objects
with arbitrary names if RFCs such as https://externals.io/message/115800
passed
I'm not super convinced about the usefulness of (object)[] in particular,
but I also think that we shouldn't artificially limit the types of
expressions supported in constant expressions -- if there's no strong
reason why something should be forbidden, it should be allowed.
From that perspective, I think the root issue here is that constant
expressions currently don't support casts at all. It's not just a matter of
being unable to write (object)[], you also can't write (int)X (but you can
write +X). I think it's perfectly reasonable to support casts in constant
expressions, and if we do, then I don't think we need to go out of the way
to forbid object casts either, so support for (object)[] should just fall
out as a special case.
Regards,
Nikita