Ffile2fix
Sign in Get started

How to fix "Typed property must not be accessed before initialization"

Fatal error: Uncaught Error: Typed property App\Services\Mailer::$client must not be accessed before initialization in /var/www/html/app/Services/Mailer.php:31

Since PHP 7.4, a typed property without a default starts in an 'uninitialized' state, not null. Reading it before anything is assigned throws this Error.

Also appears as: Typed property Foo::$bar must not be accessed before initialization · Error: Typed static property Foo::$instance must not be accessed before initialization · Cannot modify readonly property App\Dto\User::$name (related readonly error)

Common causes

  • A typed property with no default (private Client $client;) that the constructor never sets
  • A child class overrides __construct() without calling parent::__construct()
  • Objects created without the constructor, e.g. by some ORMs, unserialize() or ReflectionClass::newInstanceWithoutConstructor()
  • Setter or framework injection (setter, @required, init method) not called before use
  • A conditional path in the constructor that skips the assignment

How to fix it

  1. Find where the property should be set. Open the class and check the constructor and setters for an assignment to the named property.
  2. Initialize it in the constructor. Assign every required typed property in __construct(), or use constructor property promotion: public function __construct(private Client $client) {}.
  3. Call the parent constructor. If a child class defines its own constructor, add parent::__construct(...) so properties declared in the parent are initialized.
  4. Give optional properties a default. If the value is genuinely optional, declare it nullable with a default: private ?Client $client = null; then check for null before use.
  5. Check initialization explicitly when lazy. For lazily created values, test with isset($this->client) (which returns false for uninitialized properties) before reading.
  6. Handle objects built without constructors. For unserialize() or ORM hydration, initialize in __wakeup()/__unserialize() or a lifecycle hook, or give the property a default.

PHP 8

class Mailer
{
    public function __construct(
        private HttpClient $client,          // always set
        private ?LoggerInterface $logger = null,
    ) {}

    private function client(): HttpClient
    {
        return $this->client;
    }
}

How to stop it happening again

  • Use constructor property promotion for required dependencies
  • Give optional typed properties an explicit default
  • Always call parent::__construct() in subclasses

Frequently asked questions

Why isn't the property just null?

Untyped properties default to null, but typed properties without a default are uninitialized. This prevents a non-nullable type from silently holding null.

Does isset() work on uninitialized properties?

Yes. isset($this->prop) returns false for an uninitialized typed property without throwing, so you can use it for lazy initialization.

Should I make everything nullable to avoid this?

No. That moves the problem to null checks everywhere. Make properties nullable only when null is a valid state; otherwise initialize them in the constructor.