Navigation
 Startseite
 Fachbücher
 Anzeigenmarkt
 Forum
 Webmaster News
 Script Newsletter
 Push Meldungen
 Kontakt
 Script Installation
 Php
 Php Tutorials
 Lernpfade
 Webhoster Vergleich
 Impressum

Community-Bereich
 kostenlos Registrieren
 Anmelden
 Benutzerliste

Script Datenbank
 Script Archiv
 Script Top 20
 Screenshots
 Testberichte

Suche
 

Unsere Php Scripts
 Counter Script
 Umfrage Script
 Bilder Upload Script
 Terminverwaltung
 Simple PHP Forum
 RSS Grabber

Tools und Generatoren
 .htpasswd Generator
 md5 Generator
 base64 Generator
 Markdown to HTML
 Colorpicker
 Unix timestamp Tool
 Unit Test Generator
 TLD Liste
 Webkatalog‑Verzeichnis

Webspace-Mieten.d...
Webhosting mit Plesk aus Erfurt: Vier...
https://www.Webspace-Mieten.de
Hosterplus.de
Bekommen Sie Speicherplatz (Webspace), Domains...
https://www.Hosterplus.de
 
 
 

PHP property_exists(): Property prüfen, auch bei null

Sie befinden sich: Home > Php Tutorial > PHP property_exists(): Prop...

PHP property_exists(): Property prüfen, auch bei null
Veröffentlicht am:
03.11.2026
Hits / Besucher:
9
Sprache:
  Deutsch
Tutorial Art:
eigenes
Eingetragen von:
Merkliste:
 
Beschreibung

Die Schnittstelle des Paketdienstes liefert zu jeder Sendung ein JSON-Objekt. Manchmal fehlt das Feld email ganz, manchmal steht es mit null darin, weil der Kunde keine Adresse hinterlegt hat. Für das Skript sind das zwei verschiedene Fälle, für isset() nicht: Beide Male kommt false. Genau diese Lücke schließt PHP property_exists(). Die Funktion fragt nicht nach dem Wert, sondern danach, ob es die Property überhaupt gibt.

Illustration zum Tutorial: PHP property_exists(): Property prüfen, auch bei null

Alle Ausgaben stammen aus Testläufen mit PHP 8.4 unter Windows und Linux, beide Systeme verhielten sich gleich.

JSON, stdClass und PHP property_exists()

Wie json_decode() aus JSON ein stdClass-Objekt macht, steht in einem eigenen Tutorial. Hier interessiert, was danach mit den Feldern passiert:

<?php

$json = '{"email":null,"name":"Anna"}';
$antwort = json_decode($json);

var_dump(isset($antwort->email));
/* bool(false) */
var_dump(property_exists($antwort, 'email'));
/* bool(true) */
var_dump(property_exists($antwort, 'telefon'));
/* bool(false) */

PHP property_exists() schaut in die Klasse und in das Objekt. Ist der Name dort deklariert oder nachträglich als Property gesetzt, lautet die Antwort true, egal welcher Wert darin steht. isset() stellt eine andere Frage: Lässt sich der Wert von hier aus lesen, und ist er nicht null? Der Weg beider Funktionen im Überblick:

flowchart TD
    A[Property-Name] --> B{In Klasse deklariert?}
    B -- ja --> C[property_exists: true]
    B -- nein --> D{Dynamisch am Objekt?}
    D -- ja --> C
    D -- nein --> E[property_exists: false]
    C --> F{Von hier lesbar und nicht null?}
    F -- ja --> G[isset: true]
    F -- nein --> H[isset: false]

Zwei Ausnahmen lässt das Bild weg: Private Properties der Elternklasse gelten nicht als deklariert, und bei einem unbekannten Namen fragt isset() zusätzlich eine vorhandene __isset()-Methode.

Syntax und Parameter im Original

Die Signatur ist kurz, die Hinweise dazu sind der wichtigere Teil:

property_exists(

object|string $object_or_class,
string $property
): bool

/* object_or_class - an object or the class name
as a string; works with any
PHP class and with stdClass
property - the name of the property
return - returns true if the property
exists, false if it does not
exist.
Use it to check if a property exists in the
class or was set on the object. If the
property is null, isset() returns false.
To check for such a property, use
property_exists(): it returns true even if
the property has the value null. It checks
public, protected and private properties
defined in the class; it cannot detect
properties that are magically accessible via
__get(). A class name will use any registered
autoloaders if the class is not already known. */

Drei Dinge stecken in diesem Kommentar: null spielt keine Rolle, die Sichtbarkeit der eigenen Klasse auch nicht, und Properties, die erst über __get() entstehen, bleiben unsichtbar. Statt eines Objekts darf ein Klassenname als String stehen.

property_exists() oder isset(): der Unterschied bei null

Für Arrays gibt es dieselbe Unterscheidung schon lange: isset() gegen array_key_exists(), ausführlich beschrieben im Tutorial zum Prüfen von Array-Schlüsseln. PHP property_exists() ist das Gegenstück für Objekte. Eine Klasse mit typischen Sonderfällen zeigt, wie weit die Antworten auseinanderliegen:

<?php

class Kunde
{
public ?string $telefon = null;
private string $passwort = 'geheim';
public static int $anzahl = 0;
public int $alter;
}
$k = new Kunde();
foreach (['telefon', 'passwort', 'anzahl',
'alter', 'Telefon'] as $name) {
printf(
"%-9s %-5s %s\n",
$name,
var_export(property_exists($k, $name), true),
var_export(isset($k->$name), true)
);
}
/* telefon true false
passwort true false
anzahl true false
alter true false
Telefon false false */

Erweitert um weitere Fälle und um get_object_vars(), aufgerufen außerhalb der Klasse:

Property property_exists() isset() get_object_vars()
öffentlich, mit Wert true true enthalten
öffentlich, null true false enthalten
protected oder private true false fehlt
static true false fehlt
typisiert, noch ohne Wert true false fehlt
dynamisch gesetzt true true enthalten
nicht vorhanden oder falsch geschrieben false false fehlt

Die letzte Zeile zeigt: Property-Namen unterscheiden Groß- und Kleinschreibung, Telefon ist eine andere Property als telefon. Bei Methoden ist das anders, method_exists() fand NAME() auch dann, wenn die Methode name() heißt.

Sichtbarkeit, Vererbung und Klassennamen als String

Dass private Properties zählen, gilt nur für die eigene Klasse. Bei geerbten Properties lieferte der Test ein anderes Bild:

<?php

class Basis
{
private $geheim = 1;
protected $intern = 2;
}
class Kind extends Basis {}

var_dump(property_exists(Kind::class, 'geheim'));
/* bool(false) */
var_dump(property_exists(Kind::class, 'intern'));
/* bool(true) */
var_dump(property_exists(Basis::class, 'geheim'));
/* bool(true) */

Wer auch die privaten Properties der Elternklassen finden will, etwa für einen eigenen Mapper, läuft die Kette mit get_parent_class() ab:

<?php

class Basis
{
private $geheim = 1;
}
class Kind extends Basis {}

function hatProperty(object|string $o, string $p): bool
{
$klasse = is_object($o) ? get_class($o) : $o;
while ($klasse !== false) {
if (property_exists($klasse, $p)) {
return true;
}
$klasse = get_parent_class($klasse);
}
return false;
}
var_dump(hatProperty(new Kind(), 'geheim'));
/* bool(true) */

Mit einem Klassennamen statt eines Objekts sieht PHP property_exists() nur, was in der Klasse deklariert ist. Statische Properties gehören dazu, nachträglich am Objekt gesetzte nicht. Ein Nebeneffekt ist leicht zu übersehen: Ist die Klasse noch nicht geladen, fragt PHP den Autoloader. Bei einem unbekannten Namen kam im Test false ohne Warnung, der Autoloader war aber vorher gefragt worden. null oder eine Zahl als erstes Argument enden dagegen hart: TypeError: property_exists(): Argument #1 ($object_or_class) must be of type object|string, null given.

Typisierte Properties ohne Wert: Error beim Lesen

Eine typisierte Property ohne Standardwert existiert, hat aber noch keinen Wert. Was dieser Zustand bedeutet, erklärt das Tutorial zu Typed Properties. Für die Prüfung heißt es: PHP property_exists() meldet true, das Lesen wirft trotzdem einen Error. Ob ein Wert gesetzt wurde, verrät erst Reflection:

<?php

class Konto
{
public int $stand;
public ?string $iban = null;
}
$konto = new Konto();
$rp = new ReflectionProperty($konto, 'stand');

var_dump(property_exists($konto, 'stand'));
/* bool(true) */
var_dump($rp->isInitialized($konto));
/* bool(false) */

try {
echo $konto->stand;
} catch (Error $e) {
echo $e->getMessage();
}
/* Typed property Konto::$stand must not be
accessed before initialization */

Bei iban mit dem Wert null lieferte isInitialized() dagegen true, während isset() bei false blieb. Ein unset() auf eine typisierte Property setzt sie in den Zustand ohne Wert zurück: property_exists() bleibt true, isInitialized() wird false.

Dynamische Properties seit PHP 8.2

In Foren taucht immer wieder die Frage auf, warum sich einem Objekt eine Property zuweisen lässt, die in der Klasse gar nicht steht. Das geht, seit PHP 8.2 aber mit Protest:

<?php

class Person
{
public string $name = 'Anna';
}
$p = new Person();
$p->alter = 42;
/* Deprecated: Creation of dynamic property
Person::$alter is deprecated */

var_dump(property_exists($p, 'alter'));
/* bool(true) */
var_dump(property_exists(Person::class, 'alter'));
/* bool(false) */

Der Unterschied zwischen Objekt und Klassenname verrät die dynamische Property, das hilft beim Aufräumen alter Projekte. In PHP 8.2, 8.3, 8.4 und 8.5 blieb es im Test bei der Deprecation, die Zuweisung klappte weiterhin. Ohne Meldung arbeiten stdClass und Klassen mit dem Attribut #[AllowDynamicProperties]. Nach unset() ist eine dynamische Property wirklich weg, property_exists() meldet dann false.

__get(), method_exists() und get_object_vars() im Vergleich

Viele Frameworks liefern Modellfelder über die magische Methode __get() aus einem internen Array. Wie das funktioniert, zeigt das Tutorial zu den Magic Methods. PHP property_exists() fragt solche Methoden nie:

<?php

class Modell
{
private array $daten = ['farbe' => 'rot'];
public function __get(string $n): mixed
{
return $this->daten[$n] ?? null;
}
public function __isset(string $n): bool
{
return isset($this->daten[$n]);
}
}
$m = new Modell();
echo $m->farbe, "\n";
/* rot */
var_dump(property_exists($m, 'farbe'));
/* bool(false) */
var_dump(isset($m->farbe));
/* bool(true), über __isset() */

Das ist der häufigste Grund für die Klage, die Funktion arbeite nicht. Für Methoden ist method_exists() zuständig, und eine Property mit einer Closure darin ist keine Methode: method_exists() lieferte false, der Aufruf $obj->rechne(2) endete mit Call to undefined method.

get_object_vars() wiederum liefert nur, was von der aufrufenden Stelle aus sichtbar und initialisiert ist. Geschützte und private Properties fehlen außerhalb der Klasse, innerhalb sind sie dabei. Die Kombination array_key_exists($name, get_object_vars($obj)) erkennt also weniger und brauchte in mehreren Messreihen auf beiden Systemen das Drei- bis Achtfache der Zeit von property_exists(), das für eine Million Aufrufe zwischen 8 und 20 ms lag. Am schnellsten war isset(), in jeder Messreihe wenige Millisekunden vor property_exists(). Es prüft aber den Wert, nicht den Namen, und taugt deshalb nur, wenn null als fehlend gelten darf.

Praxis: Objekte aus Arrays befüllen mit PHP property_exists()

Formulardaten oder eine Importzeile sollen in ein Objekt, aber nur in Felder, die es gibt. Der naheliegende Code prüft mit property_exists() und weist zu. Im Test brach er bei einer geschützten Property mit Error: Cannot access protected property Artikel::$lager ab, bei einer privaten entsprechend. Robuster ist eine Prüfung über Reflection, die auch statische und readonly-Properties aussortiert, dazu aus PHP 8.4 virtuelle Properties und asymmetrische Sichtbarkeit wie private(set):

<?php

class Artikel
{
public string $titel = '';
protected int $lager = 0;
public int $preis = 0;
public string $gross {
get => strtoupper($this->titel);
}
}
function befuelle(object $ziel, array $daten): array
{
$gesetzt = [];
foreach ($daten as $name => $wert) {
if (!property_exists($ziel, $name)) {
continue;
}
$rp = new ReflectionProperty($ziel, $name);
if (!$rp->isPublic() || $rp->isStatic()
|| $rp->isReadOnly()
|| $rp->isPrivateSet()
|| $rp->isProtectedSet()) {
continue;
}
$virtuell = $rp->isVirtual()
&& !$rp->hasHook(PropertyHookType::Set);
if ($virtuell) {
continue;
}
$ziel->$name = $wert;
$gesetzt[] = $name;
}
return $gesetzt;
}
$a = new Artikel();
$daten = ['titel' => 'Tasse', 'lager' => 4,
'preis' => '12', 'gross' => 'X', 'farbe' => 'rot'];
echo implode(', ', befuelle($a, $daten)), "\n";
/* titel, preis */
var_dump($a->preis);
/* int(12) */

Der String '12' landete als Zahl in der typisierten Property, ein Wert wie 'abc' hätte einen TypeError ausgelöst. Die virtuelle Property gross wurde übersprungen, eine direkte Zuweisung hätte mit Property Artikel::$gross is read-only geendet. Ohne isStatic() galt eine öffentliche statische Property im Test als gesetzt: PHP meldete Accessing static property … as non static, legte eine dynamische Property an, und der statische Wert blieb unverändert. Mit private(set) oder protected(set) bricht die Zuweisung von außen sogar ab, etwa mit Cannot modify private(set) property … from global scope. Wer noch PHP 8.3 oder älter einsetzt, lässt isPrivateSet(), isProtectedSet() und die Zeilen zu isVirtual() weg, weil es asymmetrische Sichtbarkeit und Property Hooks dort nicht gibt.

Fazit

PHP property_exists() beantwortet eine einzige Frage: Gibt es diesen Namen in der Klasse oder am Objekt? Der Wert, auch null, spielt keine Rolle, ebenso wenig die Sichtbarkeit innerhalb der eigenen Klasse. Damit ist die Funktion das richtige Werkzeug für JSON-Felder mit null und für Mapper, die wissen müssen, welche Felder eine Klasse kennt.

Für alles andere braucht es eine zweite Prüfung. Ob sich ein Wert lesen lässt, sagt isset(), ob eine typisierte Property schon einen Wert hat, sagt isInitialized(), und ob eine Zuweisung von außen klappt, verrät erst Reflection. Private Properties der Elternklasse, Felder hinter __get() und falsch geschriebene Namen meldet PHP property_exists() als nicht vorhanden.

 

Tags:

 

 

Kommentare (0)

Noch keine Kommentare. Sei der Erste!

Melde dich an, um einen Kommentar zu schreiben.
Bücherregal mit drei Büchern: 'PHP 4 - Grundlagen und Profiwissen' von Hanser Verlag, 'Webdesign in a Nutshell' von O'Reilly Verlag, und 'Webgestaltung' von Galileo Computing.