19

I'm a bit confused on how constructors work in PHP.

I have a class with a constructor which gets called when I instantiate a new object.

$foo = new Foo($args);

__construct($params) is called in the class Foo and it executes the appropriate initialization code.

However when I use the class to call a static function, the constructor is called again.

$bar = Foo::some_function(); //runs the constructor from Foo

This causes the constructor to execute, running the object initialization code that I intended only for when I create a new Foo object.

Am I missing the point of how constructors work? Or is there a way to prevent __construct() from executing when I use the class to make static function calls?

Should I use a "factory" function instead to do the object initialization? If so, what's the point of the constructor then?

::EDIT:: I have a form where users can upload photos to an album (create_photo.php) and an area where they can view the album (view_photos.php). Upon form submit:

$photo = new Photo($_FILES['photo'], $_POST['arg1'], ect..);

The Photo constructor creates and saves the photo. However in view_photo.php, when I call:

$photo = Photo::find_by_id($_POST['id']) //user-defined function to query database

This is causing Photo's constructor to run!

Stedy
  • 7,359
  • 14
  • 57
  • 77
bar1024
  • 231
  • 2
  • 4
  • 7
  • 8
    That can't be right. Please provide the full code where the constructor gets called by a static call! – mAu Nov 22 '11 at 17:43
  • Show your real code. What you're writing doesn't look correct. – Kerrek SB Nov 22 '11 at 17:43
  • How does the constructor look like, from what behaviour do you conclude that it runs? – markus Nov 22 '11 at 18:02
  • "Show your code" means "show us all the code that is relevant to the situation". At the very least this includes the *class definition*, of the offending class, or at least the relevant function definitions inside the class definition. – Kerrek SB Nov 22 '11 at 18:07
  • I know the constructor is definitely being called, I added some test echo statements just to be sure. At least I know now that my understanding of how the constructor is supposed to work isn't wrong. I know its a weird issue but something is running my constructor when I make static calls. I'll have to keep looking... – bar1024 Nov 22 '11 at 18:11
  • 2
    The Photo::find_by_id static method is probably creating new Photo object. – Ondřej Mirtes Nov 22 '11 at 18:31

4 Answers4

26

I see nothing that replicates your question.

See Demo: http://codepad.org/h2TMPYUV

Code:

class Foo {
    function __construct(){ 
        echo 'hi!';
    }
    static function bar(){
        return 'there';
    }
}

echo Foo::bar(); //output: "there"
Naftali
  • 144,921
  • 39
  • 244
  • 303
6

Assumption PHP 5.x

Different goals, different path

  1. create a new instance of a class (object)

    class myClassA
    {
       public $lv;
    
       public function __construct($par)
       {
           echo "Inside the constructor\n";
           $this->lv = $par;
       }
    }
    
    $a = new myClassA(11);
    $b = new myClassA(63);
    

    because we create a new object PHP calls:

    __construct($par);

    of the new object, so:

    $a->lv == 11 
    
    $b->lv == 63
    
  2. use a function of a class

    class myClassB
    {
        public static $sv;
    
        public static function psf($par)
        {
            self::$sv = $par;
        }
    }
    
    myClassB::psf("Hello!");
    $rf = &myClassB::$sv;
    myClassB::psf("Hi.");
    

    now $rf == "Hi."

    function or variabiles must defined static to be accessed by ::, no object is created calling "psf", the "class variable" sv has only 1 instance inside the class.

  3. use a singleton created by a Factory (myClassA is above)

    class myClassC
    {
    
        private static $singleton;
    
        public static function getInstance($par){
    
            if(is_null(self::$singleton)){
    
                self::$singleton = new myClassA($par);
    
            }
    
            return self::$singleton;
    
        }
    
    }
    
    $g = myClassC::getInstance("gino");
    echo "got G\n";
    
    $p = myClassC::getInstance("pino");
    echo "got P\n";
    

Using the factory (getInstance) the first time we construct a new object having $par set to gino.

Using the factory the second time $singleton has already a value that we return. No new object is created (no __construct is called, less memory & cpu is used).

The value of course is an object instanceOf myClassA and don't forget:

myClassC::$singleton->lv == "gino"

Pay attention to singletons:

What is so bad about singletons?

http://www.youtube.com/watch?v=-FRm3VPhseI

By my answer I don't want promote/demote singleton. Simply from the words in the question, I made this calc:

"static"+"__construct"="singleton"!

Community
  • 1
  • 1
Ivan Buttinoni
  • 4,110
  • 1
  • 24
  • 44
  • you should have added a disclaimer regarding singletons ans tatic classes : http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons and http://www.youtube.com/watch?v=-FRm3VPhseI – tereško Nov 23 '11 at 00:01
  • just to clarify $g = myClassC::getInstance("gino"); and then $p = myClassC::getInstance("pino"); , $g->lv and $p->lv values are the same = "gino". not gine and pino, because the constructor only run once! – Miguel Sep 22 '16 at 16:16
2

Here is my workaround:

I put method construct() in static class. Notice, it is different than __construct() which I use in regular classes.

Each class is in own file, so I lazy load that file on first use of class. This gives me event of first use of class.

spl_autoload_register(function($class) {

    include_once './' . $class . '.php';

    if (method_exists($class, 'construct')) {
        $class::construct();
    }
});
Martin
  • 1,312
  • 1
  • 15
  • 18
0

I define class properties as array in a static method and call them via the method. I'm not sure if it's the best solution or not but works great.

Example:

    class Foo
    {
      private static construct_method()
      {
        return [
          'one' => 1,
          'two' => 2
        ];
      }

      public static any_method()
      {
        return self::construct_method()['one'] + self::construct_method()['two'];
      }

    }

    echo Foo::any_method(); // 3
senera
  • 21
  • 3