150

I want to create a static class in PHP and have it behave like it does in C#, so

  1. Constructor is automatically called on the first call to the class
  2. No instantiation required

Something of this sort...

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

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

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

Hello::greet(); // Hello There!
aleemb
  • 31,265
  • 19
  • 98
  • 114
  • Could you briefly explain what a static class is supposed to behave like? Is it the implementation of a Utility? – xtofl Jan 22 '09 at 11:04
  • Just throwing my own opinion out there, but from my experience in PHP, for sanity, testability, and scalability's sake, static classes should be pretty much entirely stateless, present a more functional programming-like api than an object oriented one, and generally are best used as accessibility facades for fully instantiated objects or utility wrappers for helpers or similar constructs if they are even used at all. – mopsyd Oct 27 '17 at 03:01

6 Answers6

214

You can have static classes in PHP but they don't call the constructor automatically (if you try and call self::__construct() you'll get an error).

Therefore you'd have to create an initialize() function and call it in each method:

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


?>
James Jones
  • 3,850
  • 5
  • 25
  • 44
Greg
  • 316,276
  • 54
  • 369
  • 333
  • 21
    I quite often do this just to wrap functions up all in one place. IE Utility::doSomethingUseful(); – smack0007 Jan 22 '09 at 10:57
  • 17
    Instead of `Therefore you'd have to create an initialize() function and call it in each method:` it would be easier to make `initialize` a public function and call it right after the declaration of the class. – chacham15 Apr 15 '13 at 02:00
  • 4
    I know this is pretty old, but now you could use magic [__callStatic](http://php.net/manual/en/language.oop5.overloading.php#object.callstatic) so when you call any static method or anything, it will first call `__callStatic`, there you could see if it was initialized and then do `self::$method` or whatever you are calling. If it is still calling the method directly, try changing everything to private and see there. – matiaslauriti Oct 05 '17 at 21:37
  • 1
    What happens if two threads call greet at the same time? As there is no synchronisation, won't initialise be called twice (which in this case is ok, but in many other cases would not). Or is php single threaded and non-preemptive like node? – John Little Nov 21 '17 at 13:40
57

In addition to Greg's answer, I would recommend to set the constructor private so that it is impossible to instantiate the class.

So in my humble opinion this is a more complete example based on Greg's one:

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


?>
Community
  • 1
  • 1
Phil
  • 3,282
  • 1
  • 20
  • 16
  • 1
    This is a great approach, the construct function can however not be implemented if your singelton inherits from certain objects that require a public constructor. – Eric Herlitz Dec 15 '13 at 17:40
  • 4
    @EricHerlitz This question isn't about singletons, it's about static classes. Why would you want to create a static class that inherits from a class that's meant to be instantiated? – Mark Amery Mar 06 '14 at 15:22
  • 3
    Equally declaring the class as abstract with prevent it from being instantiated and still allow calls to static methods. – bstoney Apr 15 '15 at 03:28
25

you can have those "static"-like classes. but i suppose, that something really important is missing: in php you don't have an app-cycle, so you won't get a real static (or singleton) in your whole application...

see Singleton in PHP

Community
  • 1
  • 1
5
final Class B{

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

the stucture of b is calld a singeton handler you can also do it in a

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

this is the singleton use $a = a::getA(...);

borrel
  • 911
  • 9
  • 17
3

I generally prefer to write regular non static classes and use a factory class to instantiate single ( sudo static ) instances of the object.

This way constructor and destructor work as per normal, and I can create additional non static instances if I wish ( for example a second DB connection )

I use this all the time and is especially useful for creating custom DB store session handlers, as when the page terminates the destructor will push the session to the database.

Another advantage is you can ignore the order you call things as everything will be setup on demand.

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

The DB class...

class clsDB {

    $regular_public_variables = "whatever";

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

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

Anywhere you want to use it just call...

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

Then just treat all methods as non static ( because they are )

echo $static_instance->getvar();
dave.zap
  • 491
  • 4
  • 13
  • 1
    This is actually a singleton pattern implementation, and should really not be used - stick to dependency injection instead, which is testable and makes it easy to debug. – Thomas Hansen Aug 29 '14 at 07:40
  • 1
    Can you give an example of how to use dependency injection for this answer and how that makes it more testable? – cjsimon Apr 23 '18 at 23:09
2

object cannot be defined staticly but this works

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();
borrel
  • 911
  • 9
  • 17
  • 2
    Andreas Niedermair: thats how php works (app-cycle= a single request) But a singleton(on one that lives in the request) is a possebility in php( in php a singleton is a object that has 1 instance(within the app-cycle) – borrel Dec 09 '10 at 10:43