Ist es möglich, statische Klassen in PHP zu erstellen (wie in C #)?

139

Ich möchte eine statische Klasse in PHP erstellen und sie sich wie in C # verhalten lassen

  1. Der Konstruktor wird beim ersten Aufruf der Klasse automatisch aufgerufen
  2. Keine Instanziierung erforderlich

So etwas ...

static class Hello {
    private static $greeting = 'Hello';

    private __construct() {
        $greeting .= ' There!';
    }

    public static greet(){
        echo $greeting;
    }
}

Hello::greet(); // Hello There!
Aleemb
quelle
Können Sie kurz erklären, wie sich eine statische Klasse verhalten soll? Ist es die Implementierung eines Dienstprogramms?
xtofl
Ich möchte nur meine eigene Meinung äußern, aber aus meiner Erfahrung mit PHP sollten statische Klassen aus Gründen der Vernunft, Testbarkeit und Skalierbarkeit so gut wie vollständig zustandslos sein, eine funktionalere programmierähnliche API aufweisen als eine objektorientierte und im Allgemeinen Am besten als Barrierefreiheitsfassaden für vollständig instanziierte Objekte oder als Utility-Wrapper für Helfer oder ähnliche Konstrukte, wenn sie überhaupt verwendet werden.
Mopsyd

Antworten:

200

Sie können statische Klassen in PHP haben, aber sie rufen den Konstruktor nicht automatisch auf (wenn Sie versuchen, ihn aufzurufen self::__construct(), wird eine Fehlermeldung angezeigt).

Daher müssten Sie eine initialize()Funktion erstellen und in jeder Methode aufrufen:

<?php

class Hello
{
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>
Greg
quelle
20
Ich mache das ziemlich oft, um Funktionen an einem Ort zusammenzufassen. IE Utility :: doSomethingUseful ();
smack0007
16
Stattdessen Therefore you'd have to create an initialize() function and call it in each method:wäre es einfacher, initializeeine öffentliche Funktion zu erstellen und sie direkt nach der Deklaration der Klasse aufzurufen.
Chacham15
4
Ich weiß, dass dies ziemlich alt ist, aber jetzt können Sie magic __callStatic verwenden. Wenn Sie also eine statische Methode oder etwas anderes aufrufen __callStatic, wird es zuerst aufgerufen . Dort können Sie sehen, ob es initialisiert wurde, und dann tun self::$methododer was auch immer Sie aufrufen. Wenn die Methode immer noch direkt aufgerufen wird, ändern Sie alles in privat und sehen Sie dort.
Matiaslauriti
1
Was passiert, wenn zwei Threads gleichzeitig greet aufrufen? Da es keine Synchronisation gibt, wird die Initialisierung nicht zweimal aufgerufen (was in diesem Fall in Ordnung ist, in vielen anderen Fällen jedoch nicht). Oder ist PHP Single Threaded und nicht präemptiv wie Node?
John Little
53

Zusätzlich zu Gregs Antwort würde ich empfehlen, den Konstruktor auf privat zu setzen, damit es unmöglich ist, die Klasse zu instanziieren.

Meiner bescheidenen Meinung nach ist dies ein vollständigeres Beispiel, das auf Gregs basiert:

<?php

class Hello
{
    /**
     * Construct won't be called inside this class and is uncallable from
     * the outside. This prevents instantiating this class.
     * This is by purpose, because we want a static class.
     */
    private function __construct() {}
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>
Phil
quelle
1
Dies ist ein großartiger Ansatz. Die Konstruktfunktion kann jedoch nicht implementiert werden, wenn Ihr Singelton von bestimmten Objekten erbt, für die ein öffentlicher Konstruktor erforderlich ist.
Eric Herlitz
4
@EricHerlitz Bei dieser Frage geht es nicht um Singletons, sondern um statische Klassen. Warum sollten Sie eine statische Klasse erstellen, die von einer Klasse erbt, die instanziiert werden soll?
Mark Amery
3
Wenn Sie die Klasse gleichermaßen als abstrakt deklarieren und verhindern, dass sie instanziiert wird, können Sie weiterhin statische Methoden aufrufen.
Bstoney
24

Sie können diese "statischen" ähnlichen Klassen haben. aber ich nehme an, dass etwas wirklich Wichtiges fehlt: In PHP haben Sie keinen App-Zyklus, so dass Sie in Ihrer gesamten Anwendung keine echte Statik (oder Singleton) erhalten ...

siehe Singleton in PHP

Andreas Niedermair
quelle
1
Statische Klassen und Singletons sind nur zwei verschiedene Dinge.
Max Cuttins
4
final Class B{

    static $staticVar;
    static function getA(){
        self::$staticVar = New A;
    }
}

Die Struktur von b wird als Singeton-Handler bezeichnet. Sie können dies auch in a tun

Class a{
    static $instance;
    static function getA(...){
        if(!isset(self::$staticVar)){
            self::$staticVar = New A(...);
        }
        return self::$staticVar;
    }
}

Dies ist die Singleton-Verwendung $a = a::getA(...);

Borrel
quelle
3

Im Allgemeinen bevorzuge ich es, reguläre nicht statische Klassen zu schreiben und eine Factory-Klasse zu verwenden, um einzelne (sudostatische) Instanzen des Objekts zu instanziieren.

Auf diese Weise arbeiten Konstruktor und Destruktor wie gewohnt, und ich kann auf Wunsch zusätzliche nicht statische Instanzen erstellen (z. B. eine zweite DB-Verbindung).

Ich verwende dies die ganze Zeit und ist besonders nützlich, um benutzerdefinierte Sitzungshandler für DB-Speicher zu erstellen, da der Destruktor die Sitzung beim Beenden der Seite in die Datenbank überträgt.

Ein weiterer Vorteil ist, dass Sie die Reihenfolge, in der Sie Dinge aufrufen, ignorieren können, da alles bei Bedarf eingerichtet wird.

class Factory {
    static function &getDB ($construct_params = null)
    {
        static $instance;
        if( ! is_object($instance) )
        {
            include_once("clsDB.php");
            $instance = new clsDB($construct_params);   // constructor will be called
        }
        return $instance;
    }
}

Die DB-Klasse ...

class clsDB {

    $regular_public_variables = "whatever";

    function __construct($construct_params) {...}
    function __destruct() {...}

    function getvar() { return $this->regular_public_variables; }
}

Überall, wo Sie es verwenden möchten, rufen Sie einfach an ...

$static_instance = &Factory::getDB($somekickoff);

Dann behandeln Sie einfach alle Methoden als nicht statisch (weil sie es sind)

echo $static_instance->getvar();
dave.zap
quelle
1
Dies ist eigentlich eine Singleton-Pattern-Implementierung und sollte wirklich nicht verwendet werden. Halten Sie sich stattdessen an die Abhängigkeitsinjektion, die testbar ist und das Debuggen erleichtert.
Thomas Hansen
1
Können Sie ein Beispiel geben, wie die Abhängigkeitsinjektion für diese Antwort verwendet wird und wie sie dadurch testbarer wird?
cjsimon
2

Objekt kann nicht statisch definiert werden, aber das funktioniert

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();
Borrel
quelle
1
Andreas Niedermair: So funktioniert PHP (App-Zyklus = eine einzelne Anfrage) Aber ein Singleton (auf einem, der in der Anfrage lebt) ist eine Möglichkeit in PHP (in PHP ist ein Singleton ein Objekt mit 1 Instanz (innerhalb der App) Zyklus)
Borrel