PHP constructors and static functions
Asked Answered
W

4

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!

Warfield answered 22/11, 2011 at 17:40 Comment(6)
That can't be right. Please provide the full code where the constructor gets called by a static call!Todo
Show your real code. What you're writing doesn't look correct.Hunyadi
How does the constructor look like, from what behaviour do you conclude that it runs?Ipecac
"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.Hunyadi
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...Warfield
The Photo::find_by_id static method is probably creating new Photo object.Macaronic
B
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"
Bebebebeerine answered 22/11, 2011 at 17:43 Comment(0)
P
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"!

Preshrunk answered 22/11, 2011 at 19:14 Comment(2)
you should have added a disclaimer regarding singletons ans tatic classes : #138475 and youtube.com/watch?v=-FRm3VPhseISteelmaker
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!Jansen
C
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();
    }
});
Ce answered 24/12, 2013 at 21:42 Comment(1)
If you want to call __construct method, it will be new $class()Moratorium
N
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
Nikianikita answered 18/5, 2018 at 12:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.