Fixing “Attempt to read property … on null” Errors in Yii2 (PHP 8+)

-

Fixing “Attempt to read property … on null” Errors in Yii2 (PHP 8+)

What’s Going On

When you run old Yii2 code under PHP 8+, what used to be PHP notices (harmless warnings) have upgraded into fatal errors when you try to access a property on null. For example:

if ($coach_data->registration_finished_flag) { … }

If $coach_data is null (because your query found nothing), you get:

Yii\base\ErrorException: Attempt to read property "registration_finished_flag" on null

In earlier PHP versions, this might only generate a notice, allowing your app to continue. Under PHP 8, it crashes.


Why It’s Hard to Fix Everywhere

  • Large codebases often use ActiveRecord calls that can return null (e.g. findOne() or relations).
  • Checking for null in every place is tedious and error-prone.
  • You want something maintainable, ideally using modern PHP features or a centralized patch.

Three Reliable Fixes

Here are ways to reduce or eliminate these errors without rewriting your entire codebase:

Fix TypeExampleWhen It’s Useful
Null-safe operator (?->)if ($coach_data?->registration_finished_flag)Best for PHP 8+. Very concise, minimal changes per location.
Null coalescing with default value($coach_data->registration_finished_flag ?? false) or ($coach_data->category->name ?? 'None')Useful when you want a fallback value; works in PHP versions before 8 too.
Check object existence before property accessif ($coach_data && $coach_data->registration_finished_flag)Safe, explicit, works in all PHP versions.

These are standard suggestions also found on Stack Overflow and in recent Yii2 discussions. Stack Overflow


Example Code Before & After

Old code (causes error in PHP 8+):

if ($coach_data->registration_finished_flag) {
    // do something
}

Fix using null-safe operator (PHP 8+):

if ($coach_data?->registration_finished_flag) {
    // do something
}

Fix using default value (works in PHP <8 too):

if (($coach_data->registration_finished_flag ?? false)) {
    // do something
}

Fix using explicit null check:

if ($coach_data && $coach_data->registration_finished_flag) {
    // do something
}

Other Strategies for Large Codebases

If you have thousands of these property accesses, manually changing each is painful. Here are more scalable approaches:

  1. Extend your ActiveRecord models or use a BaseModel
    For every model, have a base class that defines magic __get() or a getter for missing relations that returns an empty stub object. This way, $coach_data->relation->name will return something non-null (like an object with empty or default values) instead of null.
  2. Use code analysis / automated refactoring tools
    Tools like PHPStan, Psalm, or IDEs (PhpStorm with structural search/replace) can help find property accesses and optionally insert safe access patterns (?->, ??) in bulk.
  3. Tighten your relation definitions
    In Yii2, make sure hasOne() / hasMany() relations are well-defined. If a relation may be missing, document it, or wrap relation calls with with() / joinWith() so that you can detect missing foreign keys early.

PHP 8 Feature: Null-safe Operator

The null-safe operator (?->) was introduced in PHP 8.0. It allows you to traverse object property or method chains safely, returning null immediately if any part of the chain is null. PHP.Watch

Example:

$name = $new->category?->name;

If $new->category is null, the expression stops, returns null, and avoids the fatal error.


Things That Can’t Be Done via Yii2 Config

  • There is no configuration flag in Yii2 that globally suppresses property-on-null errors for all ActiveRecord property accesses. Errors are thrown by PHP itself (or by Yii’s error handling) and cannot be disabled globally without modifying each code path. Stack Overflow
  • Using error suppression operators @ is generally discouraged—it hides issues and can lead to more subtle bugs.

Conclusion

When upgrading to PHP 8+, you’ll start seeing “Attempt to read property … on null” errors in Yii2 sooner than older versions, because PHP is now stricter. The quickest and cleanest fixes are:

  • Use the null-safe operator (?->)
  • Use null coalescing (??) to provide default values
  • Add conditional checks (if ($obj && ...))

For large legacy codebases, combine one or more of these with base model overrides or analysis tools to avoid manual changes everywhere.

Your specific case about foreign key being null is exactly why ?-> works so well—it avoids errors when property is accessed on null, silently returning null instead (if property doesn’t exist) or allowing you to default.

If you want, I can prepare a patch file with sample regex replacements (e.g. search ->registration_finished_flag and replace with ?->registration_finished_flag ?? false) so you can do bulk editing.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Recent comments