È possibile creare classi statiche in PHP (come in C #)?


139

Voglio creare una classe statica in PHP e farla comportare come in C #, quindi

  1. Il costruttore viene chiamato automaticamente alla prima chiamata alla classe
  2. Nessuna istanza richiesta

Qualcosa del genere ...

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

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

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

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

Potresti spiegare brevemente come dovrebbe comportarsi una classe statica? È l'implementazione di un'utilità?
xtofl

Semplicemente esprimendo la mia opinione, ma dalla mia esperienza in PHP, per ragioni di sanità mentale, testabilità e scalabilità, le classi statiche dovrebbero essere praticamente completamente apolidi, presentare un'API più simile alla programmazione di una orientata agli oggetti, e generalmente lo sono meglio usato come facciate di accessibilità per oggetti completamente istanziati o involucri di utilità per aiutanti o costrutti simili se vengono addirittura utilizzati.
mopsyd,

Risposte:


200

Puoi avere classi statiche in PHP ma non chiamano automaticamente il costruttore (se provi a chiamare self::__construct()otterrai un errore).

Pertanto dovresti creare una initialize()funzione e chiamarla in ciascun metodo:

<?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!


?>

20
Lo faccio abbastanza spesso solo per racchiudere le funzioni in un unico posto. IE Utility :: doSomethingUseful ();
smack0007,

16
Invece Therefore you'd have to create an initialize() function and call it in each method:sarebbe più semplice creare initializeuna funzione pubblica e chiamarla subito dopo la dichiarazione della classe.
chacham15,

4
So che questo è piuttosto vecchio, ma ora potresti usare __callStatic magico, quindi quando chiami qualsiasi metodo statico o altro, chiamerà prima __callStatic, lì potrai vedere se è stato inizializzato e quindi fare self::$methodo qualunque cosa tu stia chiamando. Se sta ancora chiamando direttamente il metodo, prova a cambiare tutto in privato e vedi lì.
matiaslauriti,

1
Cosa succede se due thread chiamano greet contemporaneamente? Poiché non c'è sincronizzazione, l'inizializzazione non verrà chiamata due volte (che in questo caso è ok, ma in molti altri casi non lo farebbe). O php è single threaded e non preventivo come il nodo?
John Little,

53

Oltre alla risposta di Greg, consiglierei di impostare il costruttore come privato in modo che sia impossibile creare un'istanza della classe.

Quindi, a mio modesto parere, questo è un esempio più completo basato su quello di Greg:

<?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!


?>

1
Questo è un ottimo approccio, tuttavia la funzione di costruzione non può essere implementata se il tuo singelton eredita da determinati oggetti che richiedono un costruttore pubblico.
Eric Herlitz,

4
@EricHerlitz Questa domanda non riguarda i singoli, si tratta di classi statiche. Perché dovresti creare una classe statica che eredita da una classe che deve essere istanziata?
Mark Amery,

3
Dichiarare allo stesso modo la classe come astratta con evita che venga istanziata e consentire comunque chiamate a metodi statici.
bstoney,

24

puoi avere quelle classi "statiche". ma suppongo che manchi qualcosa di veramente importante: in php non hai un ciclo di app, quindi non otterrai un vero statico (o singleton) in tutta la tua applicazione ...

vedi Singleton in PHP


1
Classi statiche e singoli sono solo 2 cose diverse.
Max Cuttins,

4
final Class B{

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

la struttura di b è chiamata un gestore singeton puoi anche farlo in a

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

questo è l'uso singleton $a = a::getA(...);


3

In genere preferisco scrivere normali classi non statiche e utilizzare una classe factory per istanziare singole istanze (sudo statiche) dell'oggetto.

In questo modo il costruttore e il distruttore funzionano come al solito e, se lo desidero, posso creare ulteriori istanze non statiche (ad esempio una seconda connessione DB)

Lo uso sempre ed è particolarmente utile per la creazione di gestori di sessioni di archivio DB personalizzati, poiché quando la pagina termina il distruttore invierà la sessione al database.

Un altro vantaggio è che puoi ignorare l'ordine che chiami le cose poiché tutto sarà impostato su richiesta.

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;
    }
}

La classe DB ...

class clsDB {

    $regular_public_variables = "whatever";

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

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

Ovunque tu voglia usarlo basta chiamare ...

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

Quindi tratta tutti i metodi come non statici (perché lo sono)

echo $static_instance->getvar();

1
Questa è in realtà un'implementazione del modello singleton e non dovrebbe davvero essere usata - attenersi invece all'iniezione di dipendenza, che è testabile e rende facile il debug.
Thomas Hansen,

1
Puoi fare un esempio di come utilizzare l'iniezione di dipendenza per questa risposta e in che modo la rende più testabile?
cjsimon,

2

l'oggetto non può essere definito staticamente ma funziona

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();

1
Andreas Niedermair: ecco come funziona php (app-cycle = una singola richiesta) Ma un singleton (su uno che vive nella richiesta) è una possibilità in php (in php un singleton è un oggetto che ha 1 istanza (all'interno dell'app- ciclo)
Borrel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.