3

I'm thinking about putting every class into a separate file and doing the static initialization outside of the class definition.

The problem with this is the fact that the initialization will happen before the said class is actually needed (it will happen when the file which contains the class is included for the first time). It's a problem, because it may happen that the class won't be used at all, hence the initialization is unnecessary. And I think the practice of including the used files not in the beginning of your code is simply a dirty technique.

If anybody has a viable solution to this problem, I would greatly appreciate it.

Attila Kun
  • 2,215
  • 2
  • 23
  • 33
  • Where do you think you need static initializers? If you are more clear about what you're trying to do, we can help you better. I have never needed them; you're probably overthinking this. – ryeguy Sep 15 '09 at 18:00
  • 2
    I need them to establish connection to a database. But please realize that explaining why I shouldn't do it that way, won't really solve the problem, which - as I suspect - is not mine exclusively. – Attila Kun Sep 15 '09 at 18:05

5 Answers5

3

Take a look at code like this. It uses a singleton instance of the database yet you can still create instances of the class:

class DB
{
    private static $_db;

    public static function pdo()
    {
        if (is_null(self::$_db))
        {
            self::$_db=new PDO('pgsql:host=localhost;
                                port=5432;
                                dbname=testdb;
                                user=postgres;
                                password=abc123');
            self::$_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }

        return self::$_db;
    }

public static function factory()
{
    return new self;
}

private function __construct() {}

When you want an instance of the DB, you do DB::factory(). DB uses self::pdo() to return the singleton to access the database.

ryeguy
  • 65,519
  • 58
  • 198
  • 260
  • Thank you, but I've already done this. My problem is that you will have to perform the null check every time you define further methods that would use the static $_db variable to avoid throwing exceptions. This may imply some serious performance penalty. – Attila Kun Sep 15 '09 at 18:21
  • A single null check is hardly a performance hit at all. If you want to use this kind of design pattern, then this is your only choice. You asked for a workaround for something PHP does not natively support; you have to give something up. – ryeguy Sep 15 '09 at 18:25
  • 3
    I just checked, I can do about 1 million is_null comparisons per second on an older dual core laptop. Do you really think that matters? There is a point where performance doesn't matter if expressibility and ease-of-use is affected. – ryeguy Sep 15 '09 at 18:46
  • 3
    Extra 2-3 lines of code on top of every function is not a good idea and IMO its a smelly code. What if you forgot to check on top of a function which is always called after another. You will not notice it until to a point where maintenance guy changes the order of calls and find himself in trouble. – Cem Kalyoncu Sep 15 '09 at 20:37
  • @CemKalyoncu That's what unit tests are for. If you have 100% coverage of that class, then you'll notice immediately if somebody adds a method that uses an uninitialized class member. Furthermore, the idea of this abstraction is that it's tucked away neatly inside of another class -- you shouldn't need to add new methods to it. It's a DB factory and it's one purpose is to instantiate database connections and return them. Your other classes are insulated from the problem of an uninitialized database handle by using this DB factory abstraction. – Mark E. Haase Feb 10 '12 at 18:18
3

The singleton answer has a problem here... if you use the static methods before an instance of the class is created... then the static initializer has not run... so you might say that one can run the initializer in every static method... that is true but what about just getting and setting static variables... I suppose one could also use __get and __set magic functions for this... there is just a problem with the language in that it does not support static intialization... here is the way it can be done...

in file Hi.php:

class Hi{
public static $v = "0";
}

Hi::$v= "2";
// end of Hi.php file

simple use a .php file per class... and do the static initialization outside of the class definition...

thkala
  • 84,049
  • 23
  • 157
  • 201
Ed Roberts
  • 31
  • 1
2

You might look up for __autoload when a class is not found it is called and supposed to include the file contains that class. You can put static initializers in that function.

Cem Kalyoncu
  • 14,120
  • 4
  • 40
  • 62
  • 1
    You can put static initializers to the PHP files that includes the class and let __autoload to include class files for you. That way manually including class file will not cause any problem. – Cem Kalyoncu Sep 15 '09 at 20:39
  • I didn't know about __autoload, and I really like this solution. I believe this is the closest I can get to emulate the desired functionality. Another good thing is that I can avoid including every single needed file one by one; I'll just make a file which contains the __autoload method and let it do the work when it's needed. Thank you! – Attila Kun Sep 15 '09 at 22:09
  • This is what we do for our classes, managing 40-50 classes using includes is very hard. I wish there was a method to do the same for JS. We end up adding lots of unnecessary JS files. – Cem Kalyoncu Sep 15 '09 at 22:14
0

Use singleton pattern instead of static calls:

<?php
class Foo {

   protected static $_instance;

   /**
   * @return Foo
   */
   public static function getInstance() {
        return (null === self::$_instance)? 
            self::$_instance :
            self::$_instance = new Foo();
   }

   protected function __construct() {
        // initialize here
   }
}
disjunction
  • 646
  • 5
  • 8
0

This is the way I do this. The only cost is testing the $doneinit static member each time you construct.

class Foo {
   private static $doneinit=false;

   private static init() {
      // do static initialisation here

      self::$doneinit=true;
   }

   public function __construct() {
      if (!self::$doneinit) self::init();

      // go on to do the rest of construction
   }
}

Simple, and it keeps everything within the class.

Peter Bagnall
  • 1,794
  • 18
  • 22