20

By any means, is it possible to create an instance of a PHP class without calling its constructor?

I have Class A and while creating an instance of it, I'm passing a file and in the constructor of Class A I'm opening that file.

Now in Class A, there is a function which I need to call, but I don't have to pass a file, so there is no need for the constructor functionality of opening a file as none is being passed.

So my question is: Is it by any means possible to create an instance of a PHP class without calling its constructor?

Note: I cannot make a function static as I'm using some of the class properties in a function.

6 Answers 6

38

In your case I would recommend to think about redesigning your code so you don't need to do such a things, but to answer you question: yes, it is possible.

You can use ReflectionClass and it's method newInstanceWithoutConstructor introduced in PHP 5.4 Then it's very easy to create an instance of a class without calling its constructor:

$reflection = new ReflectionClass("ClassName");
$instance = $reflection->newInstanceWithoutConstructor(); //That's it!
Sign up to request clarification or add additional context in comments.

1 Comment

It's worth nothing that newInstanceWithoutConstructor() will be available with PHP 5.4.0. It is not available in any version of PHP 5.3 or below.
15

A classes constructor will always be called. There are a couple ways you could work around this, though.

The first way is to provide default values for your parameters in the constructor, and only perform certain actions on those parameters if they're set. For example:

class MyClass {
    public __construct($file = null) {
        if ($file) {
            // perform whatever actions need to be done when $file IS set
        } else {
            // perform whatever actions need to be done when $file IS NOT set
        }
        // perform whatever actions need to be done regardless of $file being set
    }
}

Another option is to extend your class such that the constructor of the child class does not call the constructor of the parent class.

class MyParentClass {
    public __construct($file) {
        // perform whatever actions need to be done regardless of $file being set
    }
}

class MyChildClass extends MyParentClass {
    public __construct() {
        // perform whatever actions need to be done when $file IS NOT set
    }
}

6 Comments

Or, as others have pointed out, a static method may best suit your needs depending on what you're trying to do.
+1 for extending the class. Maybe it is a class of a third party library that should not be changed...
Good solutions, though I believe the $file parameter still needs to exist in the extension class or else you'll get a warning with E_STRICT on. It's easy enough to ignore the variable inside the method.
wrong. You can instanciate a class without using its constructor.
i'm sorry for my rudeness. It has been explained below though: either unserialize hack, or Reflection.
|
13

Note: The solution below is for PHP 5.3 and below. As of PHP 5.4, you can also do it via Reflection as shown elsewhere on this page.

This is indeed possible.

Modified from PHPUnit_Framework_MockObject_Generator

1  $myClass = unserialize(
2      sprintf(
3          'O:%d:"%s":0:{}',
4          strlen('MyClass'), 'MyClass'
5      )
6  );

Please keep in mind, that code like this is all good and justified in a framework like PHPUnit. But if you have to have code like this in your production code, you are likely doing something very odd.


Since you asked for an explanation:

When you serialize an Object you get a string representation of the object. For instance

echo serialize(new StdClass) // gives O:8:"stdClass":0:{}

The O means object. 8 is the string length of the class name. "stdClass" is obviously the class name. The serialized object has 0 properties set (more to that later), indicated by the empty curly braces. The : are just delimiters.

Every serialized string can be recreated into its original "live" value with the unserialize function. Doing so, will circumvent the constructor. Like Charles correctly pointed out the magic method __wakeup() will be called if it is defined (just like __sleep() will be called when serializing).

In Line 3 you see a string prepared to be used with sprintf (line 2). As you can see the string length of the class name is given as %d and the class name is given as %s. This is to tell sprintf that it should use the first argument passed to it in line 4 as a digit and the second as a string. Hence, the result of the sprintf call is

'O:7:"MyClass":0:{}'

You would replace both occurences of "MyClass" in line 4 with your desired class name to create a serialized string of the class you want to instantiate without invoking the controller.

This string is then unserialized into a MyClass instance in line 1, bypassing the constructor. The unserialized instance will have all the methods of it's class and also any properties. If there is properties in MyClass, these will have their default values, unless you add different values to the serialized dummy string.

And that's already it. Nothing too magical about it.

4 Comments

This is very hard to understand. Can you add some explanation to it.
This code manually creates a serialized representation of the class, then unserializes it. This creates a new copy of the object without calling the constructor. However, it will try to call the __wakeup() method.
@Rachel @Charles did a good job summing it up already, but see my detailed explanation as well.
@Gordon: Thanks, this is very helpful for a transport neutral Webservice library I'm writing, since I don't want to go around adding _parseXML/JSON/etc static methods to every object that may be transmitted through the service. One warning I'd give to anyone thinking of using this approach is to make sure what you're putting into the serialized string is correct for the class. For instance I'm using reflection to check I've got all the properties and nothing I shouldn't have.
2

Wouldn't it be better to make the function you need static - alter class A so that it has another constructor that doesn't take any aruguments


If a class has a function that doesn't access any of the non static properties or functions in a class it can be made static.

class A{
    public function __construct($arg1){
    }

    public static function foo(){
        //do something that doesn't involve the class properties
    }
}

It can then be called without having to construct the class

//the constructor will not be called as we haven't created an instance of A
A::foo();

The difference between a static and a none static function is that the static function cannot access class properties of functions that are also static. So if in foo() you have any code that uses $this-> you can't make it static.

7 Comments

Would really appreciate if you can you elaborate more on this as I am not clear with it.
Now what is the difference by calling A->foo() vs A::foo()
@Rachel: You would call $a->foo() as a method of an instance and A::foo() as a static class method. The latter does not operate on instances of the class A and hence you don't have to call new A() to create one. To get a better idea you might want to read this article: en.wikipedia.org/wiki/Static_methods and the PHP docu: php.net/manual/en/language.oop5.static.php
You can't overload a constructor in PHP. "Fatal error: Cannot redeclare A::__construct()"
@Domenic Thanks for pointing that out. Another PHP annoyance.
|
0

Would something like this work?

class User{

  private $db;

  public function __construct(Database $db){
    $this->db = $db;
  }

  public function getUser(){
    return $this->db->query("select * from user where id = '123' limit 1");
  }

  public static function getInstance(){
    $db = new Database();
    return new User($db);
  }
}

class Other{

  public function getUser(){
    $class = User::getInstance();
    return $class->getUser();
  }
}

2 Comments

Yes, if Database class have no params in constructor.
@LucianDex You're right. I kept the example simple. You could inject Config $config also, but the logic is viable for OP question. I just put this here for future reference other than the accepted answer. In case someone wants an an alternative method.
-1

you could make the method static and call it from class context and not object context.

in code it would look like this:

class A {
  public static function func($txt) {
    print($txt);
  }
}

A::func('test');

1 Comment

Hmm, how this can be done, am really not sure. Would appreciate if you can give some more explanation about it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.