PHP 8.4 ist veröffentlicht

Bewertung [ Bewertung abgeben ] Artikel geschrieben am 04.12.2024 um 21:37 Uhr, aktualisiert am 07.12.2024, um 13:52 Uhr.

Diese Anpassung (RFC) soll vor allem die unzähligen Getter- und Setter-Methoden revolutionieren und damit den Code deutlich lesbarer gestalten. Gerade für "virtuelle" Methoden ist das eine spannende Änderung, mit der Klassen deutlich aufgeräumt werden können, als dies bisher der Fall war. Zusätzlich ergänzt und unterstützt die neu hinzugekommene Asymmetric Visibility (RFC) dies und vermindert zukünftigen Boilerplate-Code. Doch schauen wir uns dazu eine abgewandelte Version des offiziellen Beispiels an:

class Person
{
	public protected(set) string $id;
	
	public string $name {
		get => \trim($this->vorname . " " . $this->nachname);
	}
	
	
	public string $vorname = "Max" {
		set => \ucfirst($value);
	}
	
	public string $nachname = "Mustermann" {
		set {
			if( 1 > \strlen($value) )
			{
				throw new \InvalidArgumentException("Es ist kein leerer Nachname erlaubt.");
			}
			
			$this->nachname = $value;
		}
	}
	
	
	public function __construct()
	{
		$this->id = \uniqid(__CLASS__."_");
	}
	
	public function __set( string $key, $value )
	{
		echo "__set(".$key.", ".$value.")";
	}
	
	#[\Deprecated(
		message: "Bitte direkt auf \$id zugreifen",
		since: "8.4"
	)]
	public function getId() : string
	{
		return $this->id;
	}
}

Im Beispiel schauen wir uns zunächst die Eigenschaften $vorname und $nachname an. Wir sehen eine ganz normale Deklaration, wir wir sie heute bereits kennen. Allerdings wird die Zeile nicht mit einem Semikolon beendet, sondern es folgt ein Paar geschweifte Klammern. Hier ist es uns möglich direkt einen Getter und / oder Setter zu definieren. Man muss darauf achten, dass bei der einzeiligen Notation, nach dem Signalwort set/get ein => auftaucht, während eine anonyme Funktion mit weiteren, geschweiften Klammern eröffnet wird. Innerhalb des Setters ist der übergebenen Wert in der Variable $value vorhanden. Das kennt der ein oder andere sicherlich bereits aus anderen Sprachen. Damit entfällt auch die "unnötige" Suche nach dem richtigen Methodenname, um den Wert der Variable zu setzen und die Sprache selbst gibt uns zukünftig eine Philosophie vor. Damit entfallen zukünftig Varianten wie setName(), set_name() oder name(). Eine sehr zu begrüßende Änderung, zumal es auf alten Code keinen direkten Einfluss hat!

Zusätzlich ist es damit möglich "virtuelle" Eigenschaften sehr elegant zu deklarieren. Im Falle einer Person werden wir natürlich den Vor- und Nachnamen separat abspeichern, allerdings möchte man oft die Person mit dem gesamten Namen anschreiben. (ggf. mit ein paar weiteren Regeln für all diejenigen, die z.B. auch mit Namen aus den Niederlanden zu tun haben)
Für dieses Szenario definiert man das entsprechende Attribut, das gelesen werden soll und fügt nur einen Getter ein. Ist ein Setter vorhanden, dann kann das Attribut automatisch auch gelesen werden. Ist nur ein Getter vorhanden, endet das Schreiben dieses Attributs in der Fehlermeldung:

$P = new Person();
$P->name = "Test";
Fatal error: Uncaught Error: Property Person::$name is read-only in ...

Früher hätte man dafür eine eigene Methode benötigt, die deutlich mehr Platz beansprucht und die Methodenliste zusätzlich aufbläht. Diese Variante ist kompakt und elegant zugleich.

Asymmetric Visibility

Wenden wir uns einer kleinen Erweiterung zu, die es uns ermöglicht für den Zugriff per get und set auf die Eigenschaft jeweils eine eigene Sichtbarkeit zu legen. Das ist vor allem für systeminterne Eigenschaften von Vorteil, die durchaus von außen gelesen werden sollen, aber der Inhalt nicht virtuell ist. (d.h. aus anderen Eigenschaften zur Laufzeit zusammengesetzt wird)
Typische Beispiele dafür sind Identifier oder eine Versionsangabe. In diesem Fall erhält die Eigenschaft der Klasse zwei Sichtbarkeitsanweisungen hintereinander, wobei die erste immer die öffentliche Sichtbarkeit angibt und die zweite, gefolgt von einem zwingenden (set) die Sichtbarkeit zum Schreiben der Eigenschaft. Dabei ist außerdem zu beachten, dass die öffentliche Sichtbarkeit nicht einschränkender ist, als die schreibende Sichtbarkeit!
Ein private public(set) string $id würde zu einem Fatal error: Visibility of property Person::$id must not be weaker than set visibility führen. Ob die Eigenschaft über eine/n Methode/Konstruktor zur Laufzeit befüllt wird oder von vornherein vorbelegt, ist dabei irrelevant.

Beide Neuerungen ergänzen sich optimal für zukünftige Projekte!

Deprecated

Auch die Verarbeitung für Funktionen und Methoden, die als veraltet markiert werden, hat sich deutlich verändert. Während man in der Vergangenheit auf PHPDoc und die Interpretation durch IDEs angewiesen war, kann jetzt das neue Attribut #[\Deprecated] genutzt werden, optional sogar mit weiteren Angaben. Auch die PHP-internen Funktionen und Methoden bauen auf dem neuen Attribut auf und damit ist es auch für eigenem Code möglich die PHP-interne Verarbeitung für veraltete Methoden zu triggern. Gerade bei der Nutzung von Frameworks und einem guten error_reporting lassen sich so veraltete Codestellen schnell finden und effizient lösen. Einziger Unterschied: Die eigenen Methoden werden mit einem E_USER_DEPRECATED geworfen.

Gibt man noch die Parameter message und since an, so werden diese auch direkt in der Fehlermeldung mit angezeigt und der Code lässt sich schnell korrigieren. Dieses Attribut kann auf Funktionen, Methoden und Klassenkonstanten angewendet werden.