isset() liefert false, obwohl der Wert da ist – die __isset-Falle in TYPO3 14
Ein ViewHelper prüfte jahrelang zuverlässig, ob das gerade gerenderte Inhaltselement über ein Shortcut eingebunden wurde. Unter TYPO3 14 tat er es plötzlich nicht mehr – ohne dass irgendetwas darauf hingewiesen hätte.
Sieht richtig aus, ist es aber nicht
return $cObj->parentRecord !== []
&& isset($cObj->parentRecord['currentRecord'], $cObj->parentRecord['data']['CType'])
&& str_starts_with($cObj->parentRecord['currentRecord'], 'tt_content:');
Der Grund: ContentObjectRenderer::$parentRecord ist seit TYPO3 14 protected. Lesen lässt sich die Property trotzdem noch, weil die Klasse den PublicPropertyDeprecationTrait einbindet. Der bringt aber nicht nur __get() mit, sondern auch __isset() – und die beiden verhalten sich unterschiedlich.
vendor/typo3/cms-core/Classes/Compatibility/PublicPropertyDeprecationTrait.php
public function __isset(string $propertyName)
{
if (isset($this->deprecatedPublicProperties[$propertyName])) {
trigger_error($this->deprecatedPublicProperties[$propertyName], E_USER_DEPRECATED);
return isset($this->$propertyName);
}
return false; // fuer alles Nicht-Gelistete
}
public function __get(string $propertyName)
{
if (isset($this->deprecatedPublicProperties[$propertyName])) {
trigger_error($this->deprecatedPublicProperties[$propertyName], E_USER_DEPRECATED);
}
return property_exists($this, $propertyName) ? $this->$propertyName : null;
}
__get() liefert den echten Wert. __isset() dagegen gibt für jede Property, die nicht ausdrücklich in $deprecatedPublicProperties steht, immer false zurück – auch wenn die Daten vollständig vorhanden sind. Und isset($obj->prop['key']) geht über __isset(). Dasselbe gilt für den Null-Koaleszenz-Operator: $obj->prop['key'] ?? null ist ebenfalls immer null.
Die Lösung: erst zuweisen, dann prüfen
/** @var array<string, mixed> $parentRecord */
$parentRecord = $cObj->parentRecord; // einmal ueber __get()
return isset($parentRecord['currentRecord'], $parentRecord['data']['CType'])
&& str_starts_with($parentRecord['currentRecord'], 'tt_content:');
Sobald der Wert in einer gewöhnlichen Variablen liegt, verhält sich isset() wieder normal. Beim Suchen hilft es, im eigenen Code nach isset($cObj-> und ?? in Verbindung mit fremden Objekten zu greppen. Besonders tückisch ist, dass die Falle beim Debuggen ein zweites Mal zuschnappt: Wer den Fehler mit $obj->prop['x'] ?? null untersuchen will, bekommt wieder null und hält die Property fälschlich für leer.
Erstellt am: