it-swarm.com.de

Beste Möglichkeit, die Existenz einer Variablen in PHP zu testen. isset () ist eindeutig defekt

Aus den isset()-Dokumenten :

isset() will return FALSE if testing a variable that has been set to NULL.

Grundsätzlich prüft isset() nicht, ob die Variable überhaupt gesetzt ist, sondern ob sie auf etwas anderes als NULL gesetzt ist.

Wie kann man am besten prüfen, ob eine Variable existiert? Ich habe so etwas ausprobiert:

if(isset($v) || @is_null($v))

(Der @ ist notwendig, um die Warnung zu vermeiden, wenn $v nicht gesetzt ist.) is_null() hat jedoch ein ähnliches Problem wie isset(): es gibt TRUE für unset-Variablen zurück! Es scheint auch so zu sein:

@($v === NULL)

funktioniert genau wie @is_null($v), also auch das ist raus.

Wie sollen wir zuverlässig prüfen, ob eine Variable in PHP existiert?


Edit: Es gibt einen klaren Unterschied in PHP zwischen Variablen, die nicht gesetzt sind, und Variablen, die auf NULL gesetzt sind:

<?php
$a = array('b' => NULL);
var_dump($a);

PHP zeigt, dass $a['b'] existiert und einen NULL-Wert hat. Wenn Sie hinzufügen:

var_dump(isset($a['b']));
var_dump(isset($a['c']));

sie können die Mehrdeutigkeit sehen, von der ich mit der Funktion isset() spreche. Hier ist die Ausgabe aller drei dieser var_dump()s:

array(1) {
  ["b"]=>
  NULL
}
bool(false)
bool(false)

Weitere Bearbeitung: zwei Dinge.

Eins, ein Anwendungsfall. Ein Array wird in die Daten einer SQL UPDATE-Anweisung umgewandelt, wobei die Schlüssel des Arrays die Spalten der Tabelle sind und die Werte des Arrays die Werte, die auf jede Spalte angewendet werden sollen. Jede Spalte der Tabelle kann einen NULL-Wert enthalten, der durch die Übergabe eines NULL-Werts im Array angezeigt wird. Sie brauchen eine Möglichkeit, zwischen einem nicht vorhandenen Array-Schlüssel und einem Array-Wert zu unterscheiden, der auf NULL gesetzt ist. Das ist der Unterschied zwischen dem Aktualisieren des Spaltenwerts und dem Aktualisieren des Spaltenwerts auf NULL.

Zweitens funktioniert Zoredaches Antwort , array_key_exists() korrekt für den obigen Anwendungsfall und für alle globalen Variablen:

<?php
$a = NULL;
var_dump(array_key_exists('a', $GLOBALS));
var_dump(array_key_exists('b', $GLOBALS));

ausgänge:

bool(true)
bool(false)

Da dies praktisch überall zutrifft, kann ich feststellen, dass es zwischen den nicht vorhandenen und den Variablen NULL keine Mehrdeutigkeit gibt. Ich rufe array_key_exists() auf, der offiziell einfachste Weg in PHP, um wirklich zu überprüfen das Vorhandensein einer Variablen.

(Ich kann mir nur einen anderen Fall für Klasseneigenschaften vorstellen, für die es property_exists() gibt, das laut seiner docs ähnlich wie array_key_exists() dahingehend funktioniert, dass es richtig unterscheidet, nicht gesetzt zu sein und auf NULL gesetzt zu sein. )

182
chazomaticus

Wenn die Variable, die Sie überprüfen, im globalen Bereich liegt, können Sie Folgendes tun:

array_key_exists('v', $GLOBALS) 
94
Zoredache

Der Versuch, einen Überblick über die verschiedenen Diskussionen und Antworten zu geben:

Es gibt keine einzige Antwort auf die Frage, die alle Verwendungsmöglichkeiten von isset ersetzen kann. Einige Anwendungsfälle werden von anderen Funktionen behandelt, während andere der Prüfung nicht standhalten oder einen zweifelhaften Wert jenseits des Codes haben Golf. Andere Anwendungsfälle sind nicht "defekt" oder "inkonsistent", sondern zeigen, warum die Reaktion von isset auf null das logische Verhalten ist.

Real Use Cases (mit Lösungen)

1. Array-Schlüssel

Arrays können wie Sammlungen von Variablen behandelt werden, wobei unset und isset sie so behandeln, als wären sie. Da sie jedoch iteriert, gezählt usw. werden können, ist ein fehlender Wert nicht mit dem Wert null identisch.

In diesem Fall lautet die Antwort benutze array_key_exists() anstelle von isset().

Da dies das Array zur Überprüfung als Funktionsargument benötigt, wird PHP immer noch "Notices" auslösen, wenn das Array selbst nicht existiert. In einigen Fällen kann mit Recht argumentiert werden, dass jede Dimension zuerst initialisiert werden sollte, damit der Hinweis seine Aufgabe erfüllt. In anderen Fällen würde eine "rekursive" array_key_exists-Funktion, die nacheinander jede Dimension des Arrays prüft, dies vermeiden, wäre aber im Grunde dasselbe wie @array_key_exists. Es ist auch etwas tangential zur Behandlung von null-Werten.

2. Objekteigenschaften

In der traditionellen Theorie der "objektorientierten Programmierung" sind Verkapselung und Polymorphismus Schlüsseleigenschaften von Objekten; In einer klassenbasierten OOP -Implementierung wie PHP werden die gekapselten Eigenschaften als Teil der Klassendefinition deklariert und erhalten Zugriffsebenen (public, protected oder private).

Mit PHP können Sie einem Objekt jedoch auch dynamisch Eigenschaften hinzufügen, wie Sie es mit Schlüsseln für ein Array tun würden, und einige Leute verwenden klassenlose Objekte (technisch gesehen Instanzen des eingebauten stdClass, das keine Methoden hat) oder private Funktionalität) in ähnlicher Weise wie assoziative Arrays. Dies führt zu Situationen, in denen eine Funktion möglicherweise wissen möchte, ob dem ihr zugewiesenen Objekt eine bestimmte Eigenschaft hinzugefügt wurde.

Wie bei Array-Schlüsseln ist eine Lösung zum Überprüfen von Objekteigenschaften in der Sprache enthalten, die vernünftigerweise property_exists heißt.

Nicht gerechtfertigte Anwendungsfälle mit Diskussion

3. register_globals und andere Verschmutzung des globalen Namespaces

Das Feature register_globals fügte dem globalen Bereich Variablen hinzu, deren Namen durch Aspekte der HTTP-Anforderung bestimmt wurden (Parameter GET und POST sowie Cookies). Dies kann zu fehlerhaftem und unsicherem Code führen, weshalb er seit PHP 4.2, veröffentlicht im August 20 standardmäßig deaktiviert und in PHP 5.4, veröffentlicht im März 2012 vollständig entfernt wurde. Es ist jedoch möglich, dass auf einigen Systemen diese Funktion noch aktiviert oder emuliert ist. Es ist auch möglich, den globalen Namespace mit dem Schlüsselwort global oder dem Array $GLOBALS auf andere Weise zu "verschmutzen".

Erstens ist es unwahrscheinlich, dass register_globals selbst unerwartet eine null-Variable erzeugt, da die Werte für GET, POST und Cookie immer Zeichenfolgen sind (wobei '' weiterhin true von isset zurückgibt) und die Variablen im Sitzungsprogramm vollständig unter Kontrolle sein sollten.

Zweitens ist die Verschmutzung einer Variablen mit dem Wert null nur dann ein Problem, wenn dadurch eine vorherige Initialisierung überschrieben wird. Das "Überschreiben" einer nicht initialisierten Variablen mit null wäre nur dann problematisch, wenn Code irgendwo anders zwischen den beiden Zuständen unterscheiden würde. Allein ist diese Möglichkeit ein Argument gegen , ein solches zu machen Unterscheidung.

4. get_defined_vars und compact

Einige selten verwendete Funktionen in PHP, wie get_defined_vars und compact , ermöglichen es Ihnen, Variablennamen so zu behandeln, als wären sie Schlüssel in einem Array. Für globale Variablen erlaubt das super-globale Array $GLOBALS einen ähnlichen Zugriff und ist häufiger. Diese Zugriffsmethoden verhalten sich anders, wenn eine Variable nicht im entsprechenden Bereich definiert ist.

Wenn Sie sich entschlossen haben, eine Reihe von Variablen mithilfe eines dieser Mechanismen als Array zu behandeln, können Sie mit ihr dieselben Vorgänge ausführen wie mit einem normalen Array. Folglich siehe 1.

Funktionen, die nur existierten, um vorherzusagen, wie sich diese Funktionen verhalten werden (z. B. "Wird das von get_defined_vars zurückgegebene Array einen Schlüssel" foo "enthalten?"), Sind überflüssig, da Sie die Funktion einfach ausführen und ohne negative Auswirkungen herausfinden können .

4a. Variable Variablen ($$foo)

Obwohl dies nicht ganz mit Funktionen identisch ist, die eine Gruppe von Variablen in ein assoziatives Array umwandeln, kann und sollte dies in den meisten Fällen mit "Variablenvariablen" ("einer Variablen zuweisen, die auf der Grundlage dieser anderen Variablen benannt wurde") geschehen wurde geändert, um stattdessen ein assoziatives Array zu verwenden.

Ein Variablenname ist im Grunde die Bezeichnung, die der Programmierer einem Wert gibt. Wenn Sie es zur Laufzeit ermitteln, handelt es sich nicht wirklich um eine Bezeichnung, sondern um einen Schlüssel in einem Schlüsselwertspeicher. Praktischer gesagt, wenn Sie kein Array verwenden, verlieren Sie die Fähigkeit zu zählen, zu iterieren usw .; Es kann auch unmöglich werden, eine Variable "außerhalb" des Schlüsselwertspeichers zu haben, da sie möglicherweise von $$foo überschrieben wird.

Sobald der Code für die Verwendung eines assoziativen Arrays geändert wurde, kann er für Lösung 1 verwendet werden. Der indirekte Zugriff auf Objekteigenschaften (z. B. $foo->$property_name) kann mit Lösung 2 adressiert werden.

5. isset ist so viel einfacher zu tippen als array_key_exists

Ich bin mir nicht sicher, ob dies wirklich relevant ist, aber ja, die Funktionsnamen von PHP können manchmal ziemlich langwierig und inkonsistent sein. Anscheinend haben prähistorische Versionen von PHP die Länge eines Funktionsnamens als Hash-Schlüssel verwendet, also hat Rasmus bewusst Funktionsnamen wie htmlspecialchars erfunden, damit sie eine ungewöhnliche Anzahl von Zeichen haben ...

Zumindest schreiben wir noch kein Java, oder? ;)

6. Nicht initialisierte Variablen haben einen Typ

Die Handbuchseite zu Variablengrundlagen enthält diese Anweisung:

Nicht initialisierte Variablen haben je nach Kontext, in dem sie verwendet werden, einen Standardwert ihres Typs

Ich bin mir nicht sicher, ob es in der Zend Engine einen Begriff von "nicht initialisiertem, aber bekanntem Typ" gibt oder ob dies zu viel in die Anweisung einliest.

Klar ist, dass es keinen praktischen Unterschied zu ihrem Verhalten gibt, da das auf dieser Seite beschriebene Verhalten für nicht initialisierte Variablen mit dem Verhalten einer Variablen mit dem Wert null identisch ist. Um ein Beispiel auszuwählen, werden sowohl $a als auch $b in diesem Code als Ganzzahl 42 ausgegeben:

unset($a);
$a += 42;

$b = null;
$b += 42;

(Der erste Befehl gibt einen Hinweis auf eine nicht deklarierte Variable aus, um Sie dazu zu bringen, besseren Code zu schreiben. Es spielt jedoch keine Rolle, wie der Code tatsächlich ausgeführt wird.)

99. Erkennen, ob eine Funktion ausgeführt wurde

(Beibehaltung der letzten, da sie viel länger ist als die anderen. Vielleicht bearbeite ich sie später ...)

Betrachten Sie den folgenden Code:

$test_value = 'hello';
foreach ( $list_of_things as $thing ) {
    if ( some_test($thing, $test_value) ) {
        $result = some_function($thing);
    }
}
if ( isset($result) ) {
    echo 'The test passed at least once!';
}

Wenn some_functionnull zurückgeben kann, besteht die Möglichkeit, dass echo nicht erreicht wird, obwohl some_testtrue zurückgegeben hat. Der Programmierer wollte feststellen, wann $result noch nie festgelegt wurde, aber PHP lässt dies nicht zu.

Es gibt jedoch andere Probleme mit diesem Ansatz, die deutlich werden, wenn Sie eine äußere Schleife hinzufügen:

foreach ( $list_of_tests as $test_value ) {
    // something's missing here...
    foreach ( $list_of_things as $thing ) {
        if ( some_test($thing, $test_value) ) {
            $result = some_function($thing);
        }
    }
    if ( isset($result) ) {
        echo 'The test passed at least once!';
    }
}

Da $result niemals explizit initialisiert wird, nimmt es einen Wert an, wenn der allererste Test bestanden wird, sodass nicht festgestellt werden kann, ob nachfolgende Tests bestanden wurden oder nicht. Dies ist tatsächlich ein sehr häufiger Fehler, wenn Variablen nicht richtig initialisiert werden.

Um dies zu beheben, müssen wir etwas in der Zeile tun, in der ich kommentiert habe, dass etwas fehlt. Die naheliegendste Lösung besteht darin, $result auf einen "Endwert" zu setzen, den some_function niemals zurückgeben kann. Wenn dies null ist, funktioniert der Rest des Codes einwandfrei. Wenn es keinen natürlichen Kandidaten für einen Endwert gibt, weil some_function einen extrem unvorhersehbaren Rückgabetyp hat (was an sich wahrscheinlich ein schlechtes Zeichen ist), dann wird ein zusätzlicher boolescher Wert, z. $found könnte stattdessen verwendet werden.

Gedankenexperiment eins: die very_null-Konstante

PHP könnte theoretisch eine spezielle Konstante - sowie null - zur Verwendung als Terminalwert bereitstellen. Vermutlich wäre es illegal, dies von einer Funktion zurückzugeben, oder es würde zu null gezwungen, und das gleiche würde wahrscheinlich für die Weitergabe als Funktionsargument gelten. Das würde diesen speziellen Fall etwas einfacher machen, aber sobald Sie sich entschlossen haben, den Code neu zu faktorisieren - zum Beispiel, um die innere Schleife in eine separate Funktion zu versetzen -, wird er unbrauchbar. Wenn die Konstante zwischen Funktionen übergeben werden könnte, könnten Sie nicht garantieren, dass some_function sie nicht zurückgibt, sodass sie nicht mehr als universeller Terminalwert verwendet werden kann.

Das Argument für die Erkennung nicht initialisierter Variablen in diesem Fall läuft auf das Argument für diese spezielle Konstante hinaus: Wenn Sie den Kommentar durch unset($result) ersetzen und diesen anders als $result = null behandeln, geben Sie einen "Wert" für $result ein, der nicht weitergegeben werden kann, und kann nur von bestimmten eingebauten Funktionen erkannt werden.

Gedankenexperiment zwei: Zuweisungszähler

Eine andere Art, darüber nachzudenken, was der letzte if fragt, ist "Hat irgendetwas eine Zuordnung zu $result vorgenommen?". Anstatt es als speziellen Wert von $result zu betrachten, könnten Sie sich dies als "Metadaten" über die Variable vorstellen, ein bisschen wie Perls "Variablen-Tainting". Anstelle von isset können Sie auch has_been_assigned_to und statt unsetreset_assignment_state nennen.

Aber wenn ja, warum bei einem Booleschen anhalten? Was ist, wenn Sie wissen möchten , wie oft der Test bestanden wurde; Sie können Ihre Metadaten einfach auf eine Ganzzahl erweitern und get_assignment_count und reset_assignment_count ...

Offensichtlich hätte das Hinzufügen eines solchen Features einen Kompromiss zwischen Komplexität und Leistung der Sprache zur Folge, sodass es sorgfältig gegen die erwartete Nützlichkeit abgewogen werden müsste. Wie bei einer very_null-Konstante wäre sie nur unter sehr engen Umständen nützlich und wäre in ähnlicher Weise resistent gegen Re-Factoring.

Die hoffentlich naheliegende Frage ist, warum die Laufzeit-Engine PHP im Voraus davon ausgehen sollte, dass Sie solche Dinge im Auge behalten möchten, anstatt es Ihnen zu überlassen, dies explizit mit normalem Code zu tun.

44
IMSoP

Manchmal verliere ich mich beim Versuch, herauszufinden, welche Vergleichsoperation in einer bestimmten Situation verwendet werden soll. isset() gilt nur für nicht initialisierte oder explizit leere Werte. Das Übergeben/Zuweisen von Null ist eine hervorragende Möglichkeit, um sicherzustellen, dass ein logischer Vergleich wie erwartet funktioniert.

Es ist jedoch etwas schwierig, darüber nachzudenken. Hier ist eine einfache Matrix, die vergleicht, wie unterschiedliche Werte von verschiedenen Operationen ausgewertet werden:

|           | ===null | is_null | isset | empty | if/else | ternary | count>0 |
| -----     | -----   | -----   | ----- | ----- | -----   | -----   | -----   |
| $a;       | true    | true    |       | true  |         |         |         |
| null      | true    | true    |       | true  |         |         |         |
| []        |         |         | true  | true  |         |         |         |
| 0         |         |         | true  | true  |         |         | true    |
| ""        |         |         | true  | true  |         |         | true    |
| 1         |         |         | true  |       | true    | true    | true    |
| -1        |         |         | true  |       | true    | true    | true    |
| " "       |         |         | true  |       | true    | true    | true    |
| "str"     |         |         | true  |       | true    | true    | true    |
| [0,1]     |         |         | true  |       | true    | true    | true    |
| new Class |         |         | true  |       | true    | true    | true    |

Um die Tabelle anzupassen, habe ich die Etiketten ein wenig komprimiert:

  • $a; verweist auf eine deklarierte, aber nicht zugewiesene Variable
  • alles andere in der ersten Spalte bezieht sich auf einen zugewiesenen Wert wie:
    • $a = null;
    • $a = [];
    • $a = 0;
  • die Spalten verweisen auf Vergleichsoperationen wie:
    • $a === null
    • isset($a)
    • empty($a)
    • $a ? true : false

Alle Ergebnisse sind boolesch, true wird gedruckt und false wird weggelassen.

Sie können die Tests selbst durchführen, überprüfen Sie diese Übersicht:
https://Gist.github.com/mfdj/8165967

20
Mark Fox

Sie können das kompakte Sprachkonstrukt verwenden, um das Vorhandensein einer Nullvariablen zu testen. Nicht vorhandene Variablen werden im Ergebnis nicht angezeigt, während Nullwerte angezeigt werden.

$x = null;
$y = 'y';

$r = compact('x', 'y', 'z');
print_r($r);

// Output:
// Array ( 
//  [x] => 
//  [y] => y 
// ) 

Im Falle Ihres Beispiels:

if (compact('v')) {
   // True if $v exists, even when null. 
   // False on var $v; without assignment and when $v does not exist.
}

Für Variablen im globalen Bereich können Sie natürlich auch array_key_exists () verwenden.

B.t.w. Ich persönlich würde Situationen wie die Pest vermeiden, in denen es einen semantischen Unterschied zwischen einer nicht vorhandenen Variablen und der Variablen mit einem Nullwert gibt. PHP und die meisten anderen Sprachen glauben einfach nicht, dass es gibt.

17
Matijs

NULL erklären, logisch denken

Ich denke, die offensichtliche Antwort auf all das ist ....__: Initialisieren Sie Ihre Variablen nicht als NULL, sondern als etwas, das relevant ist für das, was sie werden sollen.

NULL richtig behandeln

NULL sollte als "nicht vorhandener Wert" behandelt werden. Dies ist die Bedeutung von NULL . Die Variable kann nicht als für PHP vorhanden klassifiziert werden, da nicht bekannt ist, um welche Art von Entität es sich handelt versuchen zu sein. Es kann auch nicht existieren, daher sagt PHP einfach "Gut, das ist nicht der Fall, weil es sowieso keinen Sinn hat und NULL ist meine Art, dies zu sagen".

Ein Argument

Lasst uns jetzt streiten. "Aber NULL ist wie 0 oder False oder ''.

Falsch, 0-FALSE- '' werden immer noch als leere Werte klassifiziert, aber sie werden als eine Art Wert oder eine vorbestimmte Antwort auf eine Frage angegeben.FALSEist die Antwort auf Ja oder Nein, '' ist die Antwort auf den Titel, den jemand eingereicht hat, und 0 ist die Antwort auf Menge oder Zeit usw. Sie sind als einige festgelegt Art der Antwort/des Ergebnisses, wodurch sie als gesetzt gelten.

NULL ist einfach keine Antwort, es sagt uns nicht Ja oder Nein und es sagt uns nicht die Zeit und es sagt uns nicht, dass ein leerer String übergeben wurde. Das ist die grundlegende Logik, um NULL zu verstehen.

Zusammenfassung

Es geht nicht darum, verrückte Funktionen zu schaffen, um das Problem zu umgehen, es ändert lediglich die Art und Weise, wie Ihr Gehirn NULL betrachtet. Wenn es NULL ist, wird davon ausgegangen, dass es nicht als etwas festgelegt ist. Wenn Sie Variablen vordefinieren, definieren Sie sie als 0, FALSE oder "" abhängig von der Art der Verwendung, die Sie für sie beabsichtigen.

Fühlen Sie sich frei, dies zu zitieren .. __ es ist aus meinem logischen Kopf :)

15
greatbigmassive

Objekteigenschaften können durch property_exists auf Existenz geprüft werden.

Beispiel aus einem Unit-Test:

function testPropertiesExist()
{
    $sl =& $this->system_log;
    $props = array('log_id',
                   'type',
                   'message',
                   'username',
                   'ip_address',
                   'date_added');

    foreach($props as $prop) {
        $this->assertTrue(property_exists($sl, $prop),
                           "Property <{$prop}> exists");
    }
}
9
Thomas

Als Ergänzung zu die Diskussion von greatbigmassive darüber, was NULL bedeutet betrachten Sie, was "die Existenz einer Variablen" tatsächlich bedeutet.

In vielen Sprachen müssen Sie jede Variable explizit deklarieren, bevor Sie sie verwenden ; Dies kann den Typ bestimmen, aber was noch wichtiger ist, es deklariert den Gültigkeitsbereich . Eine Variable "existiert" überall in ihrem Bereich und nirgendwo außerhalb - sei es eine ganze Funktion oder ein einzelner "Block".

Innerhalb seines Gültigkeitsbereichs weist eine Variable einem Label , das Sie als Programmierer ausgewählt haben, eine Bedeutung zu. Außerhalb des Gültigkeitsbereichs ist dieses Label bedeutungslos (es ist grundsätzlich unerheblich, ob Sie dasselbe Label in einem anderen Gültigkeitsbereich verwenden).

In PHP müssen Variablen nicht deklariert werden - sie werden zum Leben erweckt, sobald Sie sie benötigen. Wenn Sie zum ersten Mal in eine Variable schreiben, weist PHP dieser Variablen einen Eintrag im Speicher zu. Wenn Sie aus einer Variablen lesen, für die derzeit kein Eintrag vorhanden ist, geht PHP davon aus, dass diese Variable den Wert NULL hat.

Automatische Codequalitätserkenner warnen Sie jedoch im Allgemeinen, wenn Sie eine Variable verwenden, ohne sie zuerst zu "initialisieren". Erstens hilft dies bei der Erkennung von Tippfehlern, z. B. beim Zuweisen zu $thingId, aber beim Lesen aus $thing_id; zweitens zwingt es Sie, den Gültigkeitsbereich, über den diese Variable eine Bedeutung hat, genau wie eine Deklaration zu betrachten.

Jeder Code, der sich darum kümmert, ob eine Variable "existiert", gehört zum Gültigkeitsbereich dieser Variablen - unabhängig davon, ob sie initialisiert wurde oder nicht, haben Sie als Programmierer gegeben, dass die Bezeichnung an dieser Stelle des Codes bedeutet. Da Sie es verwenden, muss es in gewissem Sinne "existieren", und wenn es existiert, muss es einen impliziten Wert haben. In PHP ist dieser implizite Wert null.

Aufgrund der Funktionsweise von PHP ist es möglich, Code zu schreiben, der den Namespace vorhandener Variablen nicht als Bereich von Bezeichnungen behandelt, denen Sie eine Bedeutung gegeben haben, sondern als eine Art Schlüsselwertspeicher. Sie können beispielsweise folgenden Code ausführen: $var = $_GET['var_name']; $$var = $_GET['var_value'];. Nur weil du kannst, heißt das nicht, dass es eine gute Idee ist.

Es stellt sich heraus, dass PHP Schlüsselwertspeicher, sogenannte assoziative Arrays, viel besser darstellen kann. Obwohl die Werte eines Arrays wie Variablen behandelt werden können, können Sie auch Operationen für das gesamte Array ausführen. Wenn Sie ein assoziatives Array haben, können Sie mit array_key_exists() testen, ob es einen Schlüssel enthält.

Sie können Objekte auch auf ähnliche Weise verwenden und Eigenschaften dynamisch festlegen. In diesem Fall können Sie property_exists() genauso verwenden. Natürlich , wenn Sie eine Klasse definieren, können Sie deklarieren, welche Eigenschaften sie hat - Sie können sogar wählen zwischen public, private und protected Gültigkeitsbereich.

Obwohl es einen technischen Unterschied zwischen einer Variablen (im Gegensatz zu einem Array-Schlüssel oder einer Objekteigenschaft) gibt, die nicht initialisiert wurde (oder die explizit unset() war) und einer Deren Wert ist null. Jeder Code, der diesen Unterschied als bedeutungsvoll ansieht , verwendet Variablen so, wie sie nicht verwendet werden sollen.

4
IMSoP

isset prüft, ob die Variable gesetzt ist, und wenn ja, ob ihr Wert nicht NULL ist. Der letzte Teil fällt (meiner Meinung nach) nicht in den Bereich dieser Funktion. Es gibt keine anständige Problemumgehung, um zu bestimmen, ob eine Variable NULL ist, weil sie nicht oder explizit auf NULL gesetzt ist.

Hier ist eine mögliche Lösung:

$e1 = error_get_last();
$isNULL = is_null(@$x);
$e2 = error_get_last();
$isNOTSET = $e1 != $e2;
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0

Eine andere Problemumgehung besteht darin, die Ausgabe von get_defined_vars() zu prüfen:

$vars = get_defined_vars();
$isNOTSET = !array_key_exists("x", $vars);
$isNULL = $isNOTSET ? true : is_null($x);
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0
3
Salman A

Ich werde dazu noch zwei Cent hinzufügen. Ein Grund, warum dieses Problem verwirrend ist, liegt darin, dass dieses Szenario dasselbe Ergebnis zu liefern scheint, wenn der Fehlerbericht nicht voll ausgegeben wird:

$a = null;
var_dump($a); // NULL
var_dump($b); // NULL

Sie können aus diesem Ergebnis annehmen, dass der Unterschied zwischen $a = null und $b überhaupt nicht definiert ist.

Kurbelfehlerberichterstattung:

NULL

Notice: Undefined variable: b in xxx on line n
NULL

Hinweis: hat einen undefinierten Variablenfehler ausgelöst, der Ausgabewert von var_dump ist jedoch noch NULL.

PHP hat offensichtlich eine interne Fähigkeit, zwischen einer Nullvariablen und einer undefinierten Variablen zu unterscheiden. Es scheint mir, dass es eine eingebaute Funktion geben sollte, um dies zu überprüfen.

Ich glaube, die akzeptierte Antwort ist zum größten Teil gut, aber wenn ich sie implementieren würde, würde ich einen Wrapper dafür schreiben. Wie bereits erwähnt in dieser Antwort , muss ich zustimmen, dass ich noch nie eine Situation erlebt habe, in der dies ein Problem war. Ich scheine fast immer in einem Szenario zu enden, in dem meine Variablen entweder gesetzt und definiert sind oder nicht (undefiniert, nicht festgelegt, null, leer usw.). Nicht um zu sagen, dass eine Situation wie diese in der Zukunft nicht auftreten wird, aber da es sich um ein ziemlich einzigartiges Problem zu handeln scheint, bin ich nicht überrascht, dass die PHP -Entwickler sich nicht darum gekümmert haben.

2
Robbie Averill

Ich stimme nicht mit deinen Überlegungen zu NULL überein , und zu sagen, dass du deine Einstellung zu NULL ändern musst, ist seltsam.

Ich denke, isset () wurde nicht richtig entworfen, isset () sollte Ihnen sagen, ob die Variable gesetzt wurde und es sollte sich nicht um den tatsächlichen Wert der Variablen handeln.

Wenn Sie die von einer Datenbank zurückgegebenen Werte überprüfen und eine der Spalten einen NULL-Wert hat, möchten Sie trotzdem wissen, ob sie vorhanden ist, auch wenn der Wert NULL ist ... nope vertraut isset () hier nicht.

gleichfalls 

$a = array ('test' => 1, 'hello' => NULL);

var_dump(isset($a['test']));   // TRUE
var_dump(isset($a['foo']));    // FALSE
var_dump(isset($a['hello']));  // FALSE

isset () sollte so gestaltet sein, dass es so funktioniert:

if(isset($var) && $var===NULL){....

auf diese Weise überlassen wir es dem Programmierer, die Typen zu überprüfen, und isset () nicht zu überlassen, dass es nicht vorhanden ist, da der Wert NULL ist - das ist nur dummes Design

2

Wenn ich folgendes mache:

echo '<?php echo $foo; ?>' | php

Ich bekomme einen Fehler:

PHP Notice:  Undefined variable: foo in /home/altern8/- on line 1

Wenn ich folgendes mache:

echo '<?php if ( isset($foo) ) { echo $foo; } ?>' | php

Ich bekomme den Fehler nicht. 

Wenn ich eine Variable habe, die gesetzt werden sollte, mache ich normalerweise etwas wie das Folgende.

$foo = isset($foo) ? $foo : null;

oder

if ( ! isset($foo) ) $foo = null;

Auf diese Weise kann ich später im Skript $ foo sicher verwenden und wissen, dass es "gesetzt" ist und der Standardwert null ist. Später kann ich if ( is_null($foo) ) { /* ... */ }, wenn ich muss und sicher bin, dass die Variable existiert, auch wenn sie null ist.

Die vollständige isset-Dokumentation liest etwas mehr als das, was ursprünglich eingefügt wurde. Ja, es gibt für eine zuvor festgelegte Variable den Wert "false" zurück, aber es wird auch "Falsch" zurückgegeben, wenn noch keine Variable festgelegt wurde (je), und für alle Variablen, die als unset markiert wurden. Es stellt außerdem fest, dass das NULL-Byte ("\ 0") nicht als Null betrachtet wird und "true" zurückgibt.

Bestimmen Sie, ob eine Variable festgelegt ist.

Wenn eine Variable mit .__ gelöscht wurde. unset () wird nicht mehr gesetzt . isset () gibt FALSE zurück, wenn ein .__ getestet wird. Variable, die auf NULL gesetzt wurde . Beachten Sie auch, dass ein NULL-Byte ("\ 0") .__ ist. ist nicht gleichbedeutend mit PHP NULL Konstante.

1
Beau Simensen

Versuchen Sie es mit

unset($v)

Es scheint, dass die einzige Zeit, zu der eine Variable nicht gesetzt wird, darin besteht, dass sie speziell nicht gesetzt ist ($ v). Es scheint, als ob Ihre Bedeutung von 'Existenz' anders ist als die Definition von PHP. NULL ist sicherlich vorhanden, es ist NULL.

1
Joe Phillips

In all meinen Jahren der PHP - Programmierung muss ich sagen, dass es noch nie ein Problem gab, wenn isset() für eine null-Variable false zurückgibt. OTOH, ich habe Probleme mit isset() bei einem Null-Array-Eintrag festgestellt - aber array_key_exists() funktioniert in diesem Fall korrekt.

Für einige Vergleiche definiert Icon eine nicht verwendete Variable explizit als Rückgabe von &null, sodass Sie den Test is-null in Icon verwenden, um auch nach einer nicht gesetzten Variablen zu suchen. Das macht die Sache einfacher. Auf der anderen Seite verfügt Visual BASIC über mehrere Status für eine Variable, die keinen Wert hat (Null, Leer, Nothing, ...), und Sie müssen häufig nach mehr als einem dieser Werte suchen. Dies ist bekanntermaßen eine Fehlerquelle.

0
staticsan

Ich denke, die einzige vollständige Lösung besteht darin, Mitteilungen mit zu melden

error_reporting(E_ALL); // Enables E_NOTICE

Sie müssen jedoch alle Hinweise korrigieren, die unter anderem von undefinierten Variablen, Konstanten, Array-Schlüsseln und Klasseneigenschaften generiert werden. Sobald Sie dies getan haben, müssen Sie sich nicht um den Unterschied zwischen null und nicht deklarierten Variablen kümmern, und die Mehrdeutigkeit verschwindet.

Das Aktivieren von notice reporting ist möglicherweise nicht in allen Situationen eine gute Alternative, aber es gibt gute Gründe, es zu aktivieren:

Warum sollte ich E_NOTICE-Fehler beheben?

In meinem Fall arbeitete ich mehr als ein Jahr in einem Projekt ohne es, wurde aber verwendet, um Variablen zu deklarieren, daher war der Übergang schnell.

0
mikl

Der einzige Weg, um festzustellen, ob eine Variable im aktuellen Bereich definiert ist ($GLOBALS ist nicht vertrauenswürdig), ist array_key_exists( 'var_name', get_defined_vars() ).

0
Kostas Podias

Gemäß dem PHP - Handbuch für die Funktion empty () "Bestimmen Sie, ob eine Variable als leer betrachtet wird. Eine Variable wird als leer betrachtet, wenn sie nicht vorhanden ist oder wenn ihr Wert gleich FALSE ist. Empty () generiert nicht eine Warnung, wenn die Variable nicht vorhanden ist. " (Meine Betonung.) Das heißt, die leere () - Funktion sollte laut Titel Question die beste Methode sein, um das Vorhandensein einer Variablen in PHP zu testen.

Dies ist jedoch nicht gut genug, da die empty () - Funktion von einer Variablen getäuscht werden kann, die existiert und auf NULL gesetzt ist.

Ich unterbreche meine frühere Antwort, um etwas Besseres zu präsentieren, weil sie weniger umständlich ist als meine ursprüngliche Antwort (die auf diese Unterbrechung folgt, um zu vergleichen).

  function undef($dnc) //do not care what we receive
  { $inf=ob_get_contents();             //get the content of the buffer
    ob_end_clean();                     //stop buffering outputs, and empty the buffer
    if($inf>"")                         //if test associated with the call to this function had an output
    { if(false!==strpos($inf, "Undef"); //if the Word "Undefined" was part of the output
        return true;                    //tested variable is undefined
    }
    return false;                       //tested variable is not undefined
  }

Mit der obigen Funktion können zwei einfache Codezeilen erkennen, ob eine Variable undefiniert ist:

  ob_start();                           //pass all output messages (including errors) to a buffer
  if(undef($testvar===null))            //in this case the variable being tested is $testvar

Sie können diese beiden Zeilen mit allem geeigneten folgen, wie in diesem Beispiel:

    echo("variable is undefined");
  else
    echo("variable exists, holding some value");

Ich wollte den Aufruf von ob_start () und ($ testvar === null) in die Funktion einfügen und die Variable einfach an die Funktion übergeben, aber es funktioniert nicht. Selbst wenn Sie versuchen, "Referenzübergabe" der Variablen für die Funktion zu verwenden, wurde die Variable BECOMES definiert, und die Funktion kann niemals feststellen, dass sie zuvor undefiniert war. Was hier präsentiert wird, ist ein Kompromiss zwischen dem, was ich tun wollte, und dem, was tatsächlich funktioniert.

Das Vorangegangene impliziert, dass es eine andere Möglichkeit gibt, immer die Fehlermeldung "Undefined variable" zu vermeiden. (Die Annahme hier ist, dass eine solche Meldung verhindert werden soll, warum Sie testen möchten, ob eine Variable nicht definiert ist.)

   function inst(&$v) { return; }  //receive any variable passed by reference; instantiates the undefined

Rufen Sie einfach diese Funktion auf, bevor Sie etwas mit Ihrer $ testvar machen:

   inst($testvar);                //The function doesn't affect any value of any already-existing variable

Der Wert der neu instanziierten Variablen ist natürlich auf Null gesetzt!

(Unterbrechung endet)

Nach einigem Lernen und Experimentieren funktioniert also garantiert etwas:

 function myHndlr($en, $es, $ef, $el)
 { global $er;
   $er = (substr($es, 0, 18) == "Undefined variable");
   return;
 }

 $er = false;
 if(empty($testvar))
 { set_error_handler("myHndlr");
   ($testvar === null);
   restore_error_handler();
 }
 if($er)  // will be 1 (true) if the tested variable was not defined.
 { ; //do whatever you think is appropriate to the undefined variable
 }

Die Erklärung: Eine Variable $ er wird mit dem Standardwert "Kein Fehler" initialisiert. Eine "Handlerfunktion" ist definiert. Wenn $ testvar (die Variable, die wir wissen möchten, ob undefiniert ist oder nicht) den vorläufigen empty () -Funktionstest besteht, führen wir den gründlicheren Test durch. Wir rufen die Funktion set_error_handler () auf, um die zuvor definierte Handlerfunktion zu verwenden. Dann führen wir einen einfachen Identitätsvergleich mit $ testvar durch, dessen Fehler, wenn er nicht definiert wird, einen Fehler auslöst. Die Handlerfunktion erfasst den Fehler und prüft insbesondere, ob der Fehler darauf zurückzuführen ist, dass die Variable undefiniert ist. Das Ergebnis wird in die Fehlerinformationsvariable $ er gestellt, die wir später testen können, um zu tun, was wir wollen, weil wir sicher sind, ob $ testvar definiert wurde oder nicht. Da wir die Handler-Funktion nur für diesen begrenzten Zweck benötigen, stellen wir die ursprüngliche Fehlerbehandlungsfunktion wieder her. Die Funktion "myHndlr" muss nur einmal deklariert werden. Der andere Code kann an beliebige Stellen kopiert werden, für $ testvar oder jede andere Variable, die wir auf diese Weise testen möchten.

0