php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #78480 The typed properties miss an important "function"
Submitted: 2019-08-30 21:27 UTC Modified: 2021-05-27 14:45 UTC
Votes:6
Avg. Score:4.5 ± 0.8
Reproduced:5 of 5 (100.0%)
Same Version:5 (100.0%)
Same OS:4 (80.0%)
From: manchokapitancho at gmail dot com Assigned:
Status: Wont fix Package: Scripting Engine problem
PHP Version: 7.4.0beta4 OS:
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2019-08-30 21:27 UTC] manchokapitancho at gmail dot com
Description:
------------
The new PHP 7.4 feature - typed properties is a great addition to the language.
As a side effect it adds a brand new state of the class/object properties - initialized=yes/no.
If one tries to access an uninitialized property, a TypeError is being thrown.
isset($object->prop) does not trigger TypeError but it returns false if $object->prop is NULL.
The suggested check is only indirectly possible via the long construct
(new ReflectionProperty(<name>::class, '<prop>'))->isInitialized($obj)

On the other side, unset works perfectly well and returns a property back into the uninitialized state.

This write-only asymmetry is not consistent and I would expect a language construct similar to isset [e.g. is_initialized($obj->prop)] that handles this case.

Test script:
---------------
class test {
	public ?int $prop;
}
$obj = new test;

var_dump(isset($obj->prop));
var_dump(is_initialized($obj->prop));

$obj->prop = null;

var_dump(isset($obj->prop));
var_dump(is_initialized($obj->prop));



Expected result:
----------------
false
false
false
true

Actual result:
--------------
false
<missing>
false
<missing>

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-08-31 11:42 UTC] nikic@php.net
What's your use-case?

A language construct for this is very unlikely, but if this is a common and performance-critical operation, a plain function could be provided in lieu of going through reflection.
 [2019-08-31 14:05 UTC] manchokapitancho at gmail dot com
A simplified use case would be:

//orm with lazy loading from DB
class something {
 public ?<class|self> $parent;
....
function getParent() {
 if (! is_initialized($this->parent)) {
 $this->parent = //fetch from DB; value could be NULL
 }
 return $this->parent;
}
...
}


A plain function is indeed possible but the call parameters should be ($obj, 'prop) since ($obj->prop) would throw TypeError.
 [2019-09-08 18:10 UTC] jhdxr@php.net
You can use `__get` to check if it's initialized. 

see the Overloaded Properties section of the RFC(https://wiki.php.net/rfc/typed_properties_v2) as an example.
 [2019-09-09 18:10 UTC] manchokapitancho at gmail dot com
I know that I can use __get but:
1. this is a workaround (which is also not simpler than a ReflectionProperty call).
2. this is only possible if the developer has control over the class. A counterexample would be a typed property in a class exposed by a third party library.

Once again: the target is "if (!is_initialized($obj->prop)) { ... }" similar to 
"if (!isset($obj->prop)) { ... }". Isset would not generate a notice if the property is not defined and similarly is_initialized should not trigger a TypeError if $obj->prop has not been yet initialized.
 [2019-11-07 11:03 UTC] nikic@php.net
-Type: Bug +Type: Feature/Change Request
 [2020-12-04 10:15 UTC] a dot haan at iwink dot nl
[2019-09-08 18:10 UTC] jhdxr@php.net writes:

You can use `__get` to check if it's initialized. 

That's not completely true - in PHP 7.4.11.

In the first example on https://wiki.php.net/rfc/typed_properties_v2#overloaded_properties

if you do not include `unset($this->typed);`, then that example still throws:

Fatal error: Uncaught Error: Typed property Test::$typed must not be accessed before initialization in test.php on line 24

That line is the first `var_dump($test->typed);`.

Apparently this little edge case was not covered when implementing the RFC.


Regarding this mentioned issue there is another option to test for initialized state: `array_key_exists('prop', get_object_vars($obj));`
Not very neat either.
 [2020-12-04 10:50 UTC] a dot haan at iwink dot nl
Ah. With https://bugs.php.net/bug.php?id=78904 that behavior of `__get` changed. There's now a difference between uninitialized and unset properties.

That makes this request more apparent.

We used to mix types for micro cache properties; start as `false`, ending up with `null`, or an object instance. By strict checking for `false` retrieval is only done once.

Since mixing types is a bad practice, and not an option with typed properties anyway, it would be ideal if one could detect whether a property was actually uninitialized.

Sure, we can. Two ways are mentioned here. But both are verbose and require representing the property as a string.
 [2020-12-07 04:34 UTC] marrtins at dqdp dot net
I completely agree such is_initialized() would be useful for typed properties. Another use case would be for passing data to database.

Distinction would be useful:
If property hasn't been initialized - ignore it.
If property has been set to null - set database field to null.
 [2021-02-26 09:58 UTC] heiko at jerichen dot de
Working with graphql provides an other use case.
When you have a ?float field with null, it means delete this value. When not provided with graphql (would resolve to uninitialized) than ignore it.
 [2021-05-27 14:45 UTC] krakjoe@php.net
-Status: Open +Status: Wont fix
 [2021-05-27 14:45 UTC] krakjoe@php.net
After discussion as a result of https://github.com/php/php-src/pull/7029

It has transpired that we collectively do not want to go in this direction at this time, and it's highly unlikely this will change, in my opinion.

Closing as won't fix.

Anyone is free to pursue an RFC, which would be required - but ill advised given the overwhelming negative feedback.
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Thu Aug 05 12:01:23 2021 UTC