Ist das Deklarieren von Feldern für Klassen in PHP tatsächlich schädlich?

12

Betrachten Sie den folgenden Code, in dem der Setter absichtlich aufgrund eines profanen Programmierfehlers beschädigt wird, den ich in der Vergangenheit einige Male für real gemacht habe:

<?php

    class TestClass {

        private $testField;

        function setField($newVal) {
            $testField = $newVal;
            // deliberately broken; should be `$this->testField = $newVal`
        }

        function getField() {
            return $this->testField;
        }

    }

    $testInstance = new TestClass();
    $testInstance->setField("Hello world!");

    // Actually prints nothing; getField() returns null
    echo $testInstance->getField(); 

?>

Die Tatsache, dass ich $testFieldan der Spitze der Klasse deklariert habe, hilft mir, diesen Programmierfehler vor mir zu verbergen. Wenn ich das Feld nicht deklariert hätte, würde beim Aufrufen dieses Skripts etwas Ähnliches wie die folgende Warnung in mein Fehlerprotokoll gedruckt, was möglicherweise hilfreich für mein Debugging wäre - insbesondere, wenn ich einen solchen Fehler in machen würde eine große und komplizierte reale Anwendung:

PHP-Hinweis: Undefinierte Eigenschaft: TestClass :: $ testField in /var/www/test.php in Zeile 13

Mit der Erklärung gibt es keine Warnung.

Vielleicht fehlt mir etwas, aber ich kenne nur zwei Gründe, um Klassenfelder in PHP zu deklarieren: Erstens, dass die Deklarationen als Dokumentation dienen, und zweitens, dass man ohne Deklarationen die Modifikatoren privateund protectedaccess nicht verwenden kann wohl nützlich. Da das letztere Argument nicht für öffentliche Felder gilt - die Zuweisung zu einem nicht deklarierten Feld eines Objekts macht es öffentlich -, sollte ich zumindest alle meine öffentlichen Felddeklarationen auskommentieren. Die Kommentare liefern genau den gleichen Dokumentationswert, aber ich werde von Warnungen profitieren, wenn ich versuche, ein nicht initialisiertes Feld zu lesen.

Bei weiteren Überlegungen scheint es jedoch nicht sinnvoll zu sein, hier anzuhalten. Da meiner Erfahrung nach der Versuch, ein nicht initialisiertes Feld zu lesen, eine viel häufigere Fehlerursache ist als der Versuch, ein privates oder geschütztes Feld unangemessen zu lesen oder zu ändern (das erstere habe ich bereits in meiner kurzen Programmierkarriere mehrmals gemacht, das letztere jedoch nie ), es scheint mir, als wäre es eine bewährte Methode, alle Felddeklarationen - nicht nur die öffentlichen - zu kommentieren.

Was mich zögern lässt, ist, dass ich noch nie jemanden gesehen habe, der dies in seinem Code getan hat. Warum nicht? Hat das Deklarieren von Klassenfeldern, die mir nicht bekannt sind, einen Vorteil? Oder kann ich die PHP-Konfiguration auf irgendeine Weise ändern, um das Verhalten von Felddeklarationen so zu ändern, dass ich echte Felddeklarationen verwenden und trotzdem von Warnungen "Undefinierte Eigenschaften" profitieren kann? Oder gibt es noch etwas, das ich in meiner Analyse übersehen habe?

Mark Amery
quelle
1
Wohl nützlich ? Die von Ihnen angegebenen Vorteile sind äußerst wichtig. Ich würde mich wahrscheinlich rundweg weigern , an Code zu arbeiten, der keine expliziten Eigenschaftsdeklarationen enthält.
Michael
2
Der Weg, sich vor diesen Fehlern zu schützen, besteht in einer sorgfältigen Fehlerprüfung und besser in einem Unit-Test.
Michael
1
Es gibt eine integrierte PHP-Fehlerberichterstattung (eine Benachrichtigungsstufe), die Ihnen sagt, ob Sie eine Variable verwenden, ohne sie vorher zu deklarieren.
Crayon Violent
3
@MarkAmery Ich würde denken, dass ein rasantes Startup zu den wichtigsten Orten gehört, an denen strenge Unit-Tests durchgeführt werden können - da Sie den Code ständig ändern, brechen Sie ihn wahrscheinlich immer . Das ist wirklich der genaue Zweck strenger Tests und TDD. Ja, ich denke, die Verwendung von Unterstrichen kann Ihnen helfen, sich daran zu erinnern, dass Sie auf private Inhalte zugreifen, aber für mich ist die Idee, bestimmte Codierungsstandards zu übernehmen, um mich vor Fehlern zu schützen, die ich nicht machen sollte, beunruhigend. Wie tun TRUE === $variableSie sich nicht versehentlich die Zuordnung statt zu vergleichen.
Michael
1
@MarkAmery Beachten Sie auch, dass die Sichtbarkeitsschlüsselwörter von automatisierten Dokumentationstools analysiert werden , sodass sie mehr "Dokumentationswert" bieten als nur einen Kommentar, den Sie manuell eingeben würden.
Michael

Antworten:

14

Sie sollten Ihre Klasseneigenschaften immer im Voraus deklarieren. Während PHP eine dynamische Sprache ist und Sie gerne zur Laufzeit beim Erstellen Ihrer Eigenschaften unterstützt, hat dieser Pfad mehrere Nachteile.

  • Der Compiler kann deklarierte Eigenschaften optimieren. Wenn Sie eine Eigenschaft dynamisch deklarieren, ist dies ein Leistungseinbruch, da der Compiler eine dynamische Hash-Tabelle erstellen muss, um Ihre dynamischen Eigenschaften zu speichern.
  • Ich bin nicht zu 100% in diesem Fall, aber ich glaube, dass Bytecode-Optimierer wie APC nicht so nützlich sind, da sie kein vollständiges Bild Ihrer Klasse haben. (Und Optimierer wie APC sind ein Muss )
  • Macht Ihren Code 1000x schwerer zu lesen. Die Leute werden dich hassen.
  • Erhöht die Wahrscheinlichkeit, dass Sie einen Fehler machen, um das 1000-fache . (War es getId oder getID? Warten Sie, Sie haben beide verwendet. Fail.)
  • Keine automatische Vervollständigung der IDE oder Typhinweise.
  • Dokumentationsgeneratoren sehen Ihr Eigentum nicht.

Das Problem , das Du beschrieben ist eigentlich ein geringfügiger , wenn der auf das Problem im Vergleich nicht erklärt Ihre Eigenschaften in Ihrer Klassendefinition. Hier ist eine gute Lösung.

Gewöhnen Sie sich daran, Standardeinstellungen für Ihre Eigenschaften zu deklarieren.

private $testField = null;
private $testField = '';
private $testField = 0;
private $testField = []; //array()
private $testField = false;

Mit Ausnahme von Eigenschaften, in denen Objekte gespeichert werden, deckt dies die meisten Basistypen ab, die Sie speichern werden. Die Eigenschaften, in denen Objekte gespeichert werden, können in Ihrem Konstruktor festgelegt werden.

Eine gute Regel für das Klassendesign ist, dass Sie nach dem Erstellen Ihres Objekts und dem Ausführen Ihres Konstruktors keine Eigenschaften "undefiniert" haben sollten.

Jarrod Brennnesseln
quelle
Als Antwort auf Ihre 5 Nachteile: 1 (Leistung): Haben Sie eine Quelle dafür? 2 (Lesbarkeit): Ich bin mir nicht sicher, ob ich das verstehe. Der Vorschlag bestand darin, die Erklärungen zu kommentieren und nicht nur zu entfernen. Welche Lesbarkeit geht also verloren? Etwas weniger freundliche Syntaxhervorhebung und mögliche Schwierigkeiten bei der Unterscheidung von benachbarten Kommentaren, denke ich? 3: Diesen verstehe ich überhaupt nicht; könntest Du das erläutern? 4 (IDEs): Fair genug - Ich habe keine Erfahrung mit dem Codieren von PHP mit einer IDE und wusste nichts über die Typhinweise von Eclipse. 5 (doc generators): Fair genug - habe nie einen davon benutzt.
Mark Amery
Ich habe Ihre Zeile zum Auskommentieren nicht gesehen. Unabhängig davon gelten die oben genannten Punkte immer noch - woher wissen Sie, welche aktiv sind oder zu Recht auskommentiert wurden?
Jarrod Nettles
Als Antwort auf Ihre vorgeschlagene Lösung: Genau das möchte ich vermeiden - die Zuweisung von Standardwerten, auch wenn diese bedeutungslos sind und die Standardwerte niemals verwendet werden sollten. Das Problem mit diesen Standardeinstellungen (und mit der Deklaration ohne Zuweisung, die nur null zuweist) ist, dass ich, wenn ich aufgrund eines Programmierfehlers keinen Wert im Konstruktor zuweisen sollte, wenn ich sollte, anstatt PHP einen zu geben Warnung, wenn ich versuche, diesen Wert später zu verwenden - um meinen Fehler zu erkennen - scheint alles gut zu funktionieren, obwohl die Klasse fehlerhaft ist.
Mark Amery
2
@MarkAmery Ihr Programmierfehler ist jedoch im Wesentlichen ein Tippfehler. Wir haben sie alle gehabt - aber Sie versuchen, eine Bombe zu detonieren, um hier eine Fliege zu töten.
Jarrod Nettles
Du könntest Recht haben. Ich habe heute ein paar Stunden damit verbracht, einen Fehler aufzuspüren, der sich ausschließlich durch einen solchen Tippfehler verursacht hat, und war danach frustriert über die plötzliche Erkenntnis, dass ich eine Benachrichtigung erhalten hätte , wenn ich nur keine Felddeklarationen verwendet hätte sofort bekannt, wo mein Fehler war (was ich unter diesen Umständen sowieso immer gedacht hatte; ich habe keine Deklarationen realisiert, die Felder auf null initialisiert haben). Die unmittelbare Zugänglichkeit dieser Erfahrung verzerrt wahrscheinlich mein Urteil darüber, wie wahrscheinlich es ist, dass sie erneut auftritt oder wie lohnenswert es ist, sich dagegen zu verteidigen.
Mark Amery
2

Ich habe an Code gearbeitet, der dynamisch erstellte Objekteigenschaften verwendet. Ich fand die Verwendung dynamisch erstellter Objekteigenschaften ziemlich cool (meiner Meinung nach wahr). Die Ausführung meines Programms dauerte jedoch 7 Sekunden. Ich habe die dynamischen Objekteigenschaften entfernt und sie ersetzt, die als Teil jeder Klasse deklariert wurden (in diesem Fall öffentlich). Die CPU-Zeit stieg von über 7 Sekunden auf 0,177 Sekunden. Das ist ziemlich umfangreich.

Es ist möglich, dass ich bei der Verwendung dynamischer Objekteigenschaften etwas falsch gemacht habe. Es ist auch möglich, dass meine Konfiguration auf irgendeine Weise beschädigt ist. Natürlich sollte ich sagen, dass ich eine sehr einfache Vanille-PHP-Konfiguration auf meinem Computer habe.

user328304
quelle