- Solving PHPStan error “Access to an undefined property”
- Fix the name #
- Declare the property #
- PHP 8.2: Add #[AllowDynamicProperties] #
- Universal object crates #
- Add @property PHPDoc #
- Mixin #
- Extensions for popular frameworks #
- Write your own extension #
- Fix PHP Notice: Undefined property
- Typos and misspellings.
- Referencing an object property doesn’t exist yet.
- Check to see if it exists before using it.
- PHP RFC: Undefined Property Error Promotion
- Proposal
- Considerations
- Backward Incompatible Changes
- Proposed PHP Version(s)
- Voting
Solving PHPStan error “Access to an undefined property”
“Access to an undefined property Foo::$x ” is one of the most common errors you will encounter when running PHPStan. Here are all the ways you can solve it.
Fix the name #
The easiest situation you can find yourself in is that there’s a typo in the source code, and the property access needs to be corrected to the right name:
public function getName(): string - return $this->nama; + return $this->name; >
Declare the property #
In older versions of PHP you weren’t required to declare the property, and the code might have actually run fine. But for obvious type safety reasons it’s better to declare the property if it’s missing:
class HelloWorld + private string $name; + public function setName(string $name): void $this->name = $name;
PHP 8.2: Add #[AllowDynamicProperties] #
If the class is meant to have dynamic properties (when they vary from object to object), it needs to meet one of the following conditions:
- Have __get and/or __set magic methods for handling dynamic properties
- Be stdClass or extend stdClass
- Have #[AllowDynamicProperties] class attribute
Addressing these requirements will not make the PHPStan error go away, but it will allow the following solutions to work if you use PHP 8.2 or later.
Universal object crates #
Classes without predefined structure are common in PHP applications. They are used as universal holders of data — any property can be set and read on them. Notable examples include stdClass , SimpleXMLElement (these are enabled by default), objects with results of database queries etc. Use universalObjectCratesClasses key to let PHPStan know which classes with these characteristics are used in your codebase by setting them in your configuration file:
parameters: universalObjectCratesClasses: - Dibi\Row - Ratchet\ConnectionInterface
See also object shape PHPDoc type for a better alternative that lets you describe types of properties of such objects.
Add @property PHPDoc #
If the class features magic properties but these properties are always the same, you can declare them with @property PHPDocs:
/** * @property int $foo * @property-read string $bar * @property-write \stdClass $baz */ class Foo . >
Mixin #
When a class delegates unknown method calls and property accesses to a different class using __call and __get / __set , we can describe the relationship using @mixin PHPDoc tag:
class A public string $name = 'Class A'; > /** * @mixin A */ class B public function __get(string $name): mixed return (new A())->$name; > > $b = new B(); echo $b->name; // No error
Extensions for popular frameworks #
If you use a popular framework like Laravel, where model properties are often not declared on class, you can use framework-specific extensions to make PHPStan understand your code properly.
Write your own extension #
You can write your own class reflection extension to let PHPStan know which properties exist on your classes.
This solution works best if there’s custom logic in your __get() and __set() magic methods. For example if you can say “Property $name on class Foo exists if there’s a getter called getName() ”, writing a custom class reflection extension to describe this lets you solve this PHPStan error in a nice and easy way.
Fix PHP Notice: Undefined property
This is a guide on how to fix the following PHP notice:
Notice: Undefined property: stdClass::$propertyThatDoesNotExist in /path/to/file.php on line LINE NUMBER
Essentially, this notice will occur if your PHP code attempts to reference an object property that does not exist.
Typos and misspellings.
Firstly, you will need to make sure that you haven’t misspelled the name of the property that you are attempting to reference.
Take the following PHP class as an example:
As you can see, the class above has one property called User::$loggedIn.
Now, let’s do something like this:
$user = new User(); if($user->isLoggedIn)
In the code snippet above, I mistakenly referenced a property called User::$isLoggedIn. The correct name of the property is actually called User::$loggedIn. As a result, the following notice will occur:
Notice: Undefined property: User::$isLoggedIn in /path/to/file.php
The “Undefined property” notice above was caused by a simple misspelling.
While we are on the subject of typos, it is worth pointing out that class properties in PHP are case sensitive. As a result, mistakenly using a capital letter instead of a lowercase letter will also cause this error.
Referencing an object property doesn’t exist yet.
In certain cases, the property that you are attempting to reference might not exist yet. Take the following PHP class as an example:
/** * Class Person */ class Person< /** * Sets the person's name. * * @param $name */ public function setName($name)< $this->name = $name; > >
The class above has one function called setName, which dynamically creates an object property called Person::$name. i.e. The $name property will not exist until the setName function has been called. As a result, the following piece of code will result in an “Undefined property” notice:
$person = new Person(); echo $person->name;
To fix this, we will obviously need to use the setName function before we attempt to access Person::$name:
$person = new Person(); $person->setName('Maria'); echo $person->name;
Check to see if it exists before using it.
If you are unsure about whether an object property exists or not, you can always use the isset function like so:
$person = new Person(); //Using isset to check if a class //property exists or not. if(isset($person->name))< echo $person->name; >
In the PHP code above, we “fixed” the notice by adding an isset check. This works because non-existent class properties equate to null.
This kind of check may be necessary when you are dealing with JSON strings that have been decoded into a PHP object. In the past, I have come across a number of APIs that will add and omit certain JSON fields from their response depending on the circumstances.
Example: If a certain piece of data is missing from a certain record, they may remove the field from the response instead of sending it back with a null or a FALSE value. In cases like this, you will need to make use of the isset function.
Hopefully, this guide helped to clear up some confusion!
PHP RFC: Undefined Property Error Promotion
Undefined properties are those that have not yet been defined either by the presence of a property declaration, or by adding them to the properties hashmap through direct assignment, or by having them assigned by an internal function such as json_decode. Accessing an undefined property emits an E_WARNING “Undefined property ::$varName” and treats the value as if it were null, but does not otherwise interupt execution, allowing code execution to continue unabated, but potentially in an unintended state.
Undefined properties previously triggered an E_NOTICE, however this was upgraded to E_WARNING as part of the PHP 8.0 Engine Warnings RFC : https://wiki.php.net/rfc/engine_warnings — By the time this RFC would come into effect, if passed, undefined properties would have emitted a warning for 5+ years.
Proposal
This RFC proposes that accessing an undefined property is rendered illegal behaviour in the next major version of PHP, and will result in an error exception being thrown if it occurs.
For the purposes of this RFC , accessing an property means to use the property in such a way that the engine attempts to read its value for use in an expression, without accounting for the possibility of it being unset. These can be identified by the warning Undefined property ::$varName.
isset / empty / null coalesce DO account for undefined properties and as such are not covered by this RFC .
The presence of magical `get` will continue to work as it does now, and unknown properties will route to the magical `get` handler rather than cause an error (unless called within `get` on itself).
Considerations
PHP has traditionally been quite lax in its enforcement of accessing undefined values that are stored within various data structures.
There are 3 primary storage locations for values within PHP, these are:
Properties which are stored within a zend_object instance within the properties HashTable and the properties_table (which identifies their location by their slot number sourced from the class entry).
With the passing of the undefined variable error promotion RFC (https://wiki.php.net/rfc/undefined_variable_error_promotion) the first of these, variables, is scheduled for promotion to an error in PHP 9.0.
The next natural target is properties, this is in line in line with additional changes targeted at PHP 9.0 that will promote WRITING to undefined properties to be an Error (https://wiki.php.net/rfc/deprecate_dynamic_properties) unless the #[AllowDynamicProperties] attribute is set upon the class definition (stdClass includes this capability as standard).
It seems to be the natural progression that if writing to an undefined property will throw, reading from one should do likewise, to protect the user against unintended behaviour.
However, there is a potential exception to this rule, and that is the presence of stdClass, which is intended to exclusively hold unknown (to the class entry) properties, often those sourced from casting an array to an object, or from an internal function decoding some other data such as json_decode when it encounters an object, without the assoc parameter set.
While reading an undefined property on a user defined class will almost always be programmer error, historically it would not be entirely unexpected to see similar to the following code when dealing with json:
if ($obj->name) { echo "Hello " . $obj->name; }
As this now emits an E_WARNING it should be very much discouraged, but will still execute without an error as $obj->name will, if undefined, evaluate to null.
If this RFC were to pass, the developer would need to explicitly specify their intent to allow the possibility of accessing an undefined property, either via isset, empty or the null coalesce operator:
if (isset($obj->name)) { echo "Hello " . $obj->name; }
To provide the most consistent handling, this RFC proposes that stdClass will also throw an error if an undefined property is accessed.
Backward Incompatible Changes
Accessing an undefined property in a manner that currently results in an “undefined property” warning will in future result in an Error exception being thrown.
Proposed PHP Version(s)
This change is targeted for PHP 9.0.
Although the target version is mandated by our traditional breaking changes policy, it is also the intent of this RFC to give multiple years of notice that this change will be coming, affording the greatest opportunity for developers to modify their code in anticipation of this change.
A minor change will be included in the next minor version to alter the existing warning message to indicate the warning will become an error in 9.0.
Voting
Voted started on 2022-04-22, ending 2022-05-05