Extbase entities and property types
Tags: typo3, extbase, php74
Published: 2022-09-17 17:17:20

---
title: Extbase entities and property types
published: true
description: A post about extbase's problem, dealing with uninitialized properties up until and including TYPO3 10.4.
tags: TYPO3, extbase, php74
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
---

Hi folks, me again, with a post about extbase entities and property types.

We all were happy when PHP 7.4 introduced property types, right? We were able to finally switch from

```php
class Foo {
    /**
     * @var string
     */
    private $bar;

    public function __construct() {
       $this->bar = 'string';
    }
}
```

to


```php
class Foo {
    private string $bar;

    public function __construct() {
       $this->bar = 'string';
    }
}
```

except with extbase, we didn't, not to all extends. At least not until recently. Let's talk TYPO3(extbase) versions. There is this patch https://review.typo3.org/c/Packages/TYPO3.CMS/+/72005 which took care of uninitialized properties but it has only been merged to main and 11.5. So with 10.4 and prior we still have a little problem I'd like to shorty write about.

You may have noticed already that I mentioned uninitialized properties. Let me explain in detail with a couple of examples.

```php
class Foo {
    private string $bar = '';
}
```

This is an initialized property, i.e. a property which has a default value assigned. Let's say we instantiate that class and call `get_object_vars()` on it.

```php

$object = new Foo();
var_dump(get_object_vars($object));
// array(1) {
//   ["bar"]=>
//   string(0) ""
// }
```

You can see that `get_object_vars()` detects property bar, but only because it is initialized. And this is where our problem begins.

Back then, before PHP 7.4, all our properties were initialized by default with `null`. Because all properties were by default capable of being nulled.


```php
class Foo {
    /**
     * @var string
     */
    private $bar;
}
```

We find a lot of code snippets like these in legacy code bases. And while the phpdoc type expressed the desired/intended property type, it's actually wrong. The property can hold any value and is null by default. So what do we often do? We simply transform the code like this:

```php
class Foo {
    private string $bar;
}
```

But now, the property is unitialized, it may no longer be nulled and can only be assigned a string. PHP wise this is completely valid code. But transforming extbase entities like this in a code base prior to 11.5, you will run into trouble.

Up until 10.4, extbase used `get_object_vars()` to detect properties and up to and including PHP 7.3 this was no problem because all properties were always initialized and said method detected all properties. With 7.4 this changed and with extbase loosing information about the existence of properties, it may no longer set the property value when reconstituting entities from the database.

As mentioned, there is a fix in 11.5 but what if you are still on 10.4 or lower? Here's a best practice for you:

```php
class Foo {
    private string $bar = '';
}
```

If you have a property that can be initialized with a default value, like the value you also store as default in your database, do so. Even if you have a constructor that also sets a default value:

```php
class Foo {
    private string $bar = '';

    public function __construct(string $bar) {
       $this->bar = $bar;
    }
}
```

Your IDE will most likely try to tell you, you don't need the default property value, but stick with it. Also tools like PHPStan and Psalm will most likely raise an error but you need to ignore this because in this case you know better...

But what about properties that cannot be initialized, like those holding relations to other entities? Well, the only possible way is to allow and default to `null`:

```php
class Foo {
    private ?Bar $bar = null;
}
```

Even so if you know that relation cannot be null. Ugly, right?  Let's say you are using your entities only to display data (database records) in your view and your TCA makes sure, the relation is set. Well, in that case my recommendation is to throw an Exception in the getter:

```php
class Foo {
    private ?Bar $bar = null;

    public function getBar(): Bar
    {
        if ($this->bar instanceof Bar) {
            return $this->bar;
        }

        throw new \DomainException(
            'Foo::$bar is unexpectedly null'
        );
    }
}
```

I do recommend throwing an exception because that avoids a possible null value you have to deal with in underlying code. And since this case is never expected to happen, you are in the clear here.

And that's it for today. I hope this post helps you understand the framework problem and the workaround. And if you can update to 11.5, all the better!

Have a nice one.
Cheers.