¿Es posible crear clases estáticas en PHP (como en C #)?

139

Quiero crear una clase estática en PHP y hacer que se comporte como lo hace en C #, así que

  1. Se llama automáticamente al constructor en la primera llamada a la clase
  2. No se requiere instanciación

Algo de este tipo ...

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

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

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

Hello::greet(); // Hello There!
aleemb
fuente
¿Podría explicar brevemente cómo debe comportarse una clase estática? ¿Es la implementación de una utilidad?
xtofl
Solo lanzo mi propia opinión, pero desde mi experiencia en PHP, por razones de cordura, capacidad de prueba y escalabilidad, las clases estáticas deberían ser prácticamente sin estado, presentar una API más funcional como una orientada a objetos, y generalmente son se usa mejor como fachadas de accesibilidad para objetos completamente instanciados o envoltorios de utilidad para ayudantes o construcciones similares, si es que incluso se usan.
mopsyd

Respuestas:

200

Puede tener clases estáticas en PHP, pero no llaman al constructor automáticamente (si intenta llamar self::__construct(), obtendrá un error).

Por lo tanto, tendría que crear una initialize()función y llamarla en cada método:

<?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
fuente
20
A menudo hago esto solo para envolver las funciones en un solo lugar. Utilidad IE :: doSomethingUseful ();
smack0007
16
En lugar de Therefore you'd have to create an initialize() function and call it in each method:eso, sería más fácil hacer initializeuna función pública y llamarla inmediatamente después de la declaración de la clase.
chacham15
44
Sé que esto es bastante antiguo, pero ahora puedes usar magic __callStatic, así que cuando llamas a cualquier método estático o algo, primero llamará __callStatic, allí podrás ver si se inicializó y luego hacer self::$methodo lo que sea que estés llamando. Si todavía está llamando al método directamente, intente cambiar todo a privado y vea allí.
matiaslauriti
1
¿Qué sucede si dos hilos llaman a saludar al mismo tiempo? Como no hay sincronización, la inicialización no se llamará dos veces (lo que en este caso está bien, pero en muchos otros casos no lo haría). ¿O es php de un solo subproceso y no preventivo como nodo?
John Little
53

Además de la respuesta de Greg, recomendaría establecer el constructor privado para que sea imposible crear una instancia de la clase.

Entonces, en mi humilde opinión, este es un ejemplo más completo basado en el de 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!


?>
Phil
fuente
1
Este es un gran enfoque, sin embargo, la función de construcción no se puede implementar si su singelton hereda de ciertos objetos que requieren un constructor público.
Eric Herlitz
44
@EricHerlitz Esta pregunta no se trata de singletons, se trata de clases estáticas. ¿Por qué querrías crear una clase estática que herede de una clase que debe ser instanciada?
Mark Amery
3
Igualmente, declarar la clase como abstracta evita que se instancia y aún permite llamadas a métodos estáticos.
bstoney
24

puedes tener esas clases "estáticas". pero supongo que falta algo realmente importante: en php no tienes un ciclo de aplicación, por lo que no obtendrás una estática real (o singleton) en toda tu aplicación ...

ver Singleton en PHP

Andreas Niedermair
fuente
1
Clases estáticas y Singletons son solo 2 cosas diferentes.
Max Cuttins
4
final Class B{

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

la estructura de b se llama un controlador de singeton, también puede hacerlo en un

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

este es el uso singleton $a = a::getA(...);

borrel
fuente
3

Generalmente prefiero escribir clases regulares no estáticas y usar una clase de fábrica para crear instancias individuales (sudo estáticas) del objeto.

De esta forma, el constructor y el destructor funcionan de manera normal, y puedo crear instancias no estáticas adicionales si lo deseo (por ejemplo, una segunda conexión de base de datos)

Lo uso todo el tiempo y es especialmente útil para crear controladores de sesión de almacenamiento de base de datos personalizados, ya que cuando la página termina, el destructor empujará la sesión a la base de datos.

Otra ventaja es que puede ignorar el orden en que llama a las cosas, ya que todo se configurará a pedido.

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 clase DB ...

class clsDB {

    $regular_public_variables = "whatever";

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

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

En cualquier lugar que desee usar, simplemente llame ...

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

Luego, trate todos los métodos como no estáticos (porque lo son)

echo $static_instance->getvar();
dave.zap
fuente
1
Esta es en realidad una implementación de patrón singleton, y realmente no debería usarse: en su lugar, adhiérase a la inyección de dependencia, que es comprobable y facilita la depuración.
Thomas Hansen
1
¿Puede dar un ejemplo de cómo usar la inyección de dependencia para esta respuesta y cómo eso la hace más comprobable?
cjsimon
2

el objeto no se puede definir estáticamente pero esto funciona

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();
borrel
fuente
1
Andreas Niedermair: así es como funciona php (app-cycle = una sola solicitud) Pero un singleton (en uno que vive en la solicitud) es una posibilidad en php (en php un singleton es un objeto que tiene 1 instancia (dentro de la aplicación- ciclo)
borrel