tags:

views:

147

answers:

5

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

I have Class A and while creating an instance of it am passing file and in constructor of Class A am opening the file.

Now in Class A, there is function which I need to call but am not required to pass file and so there is not need to use constructor functionality of opening file as am not passing file.

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

Note I cannot make function static as am using some of the class properties in function.

+3  A: 

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.

Yacoby
Would really appreciate if you can you elaborate more on this as I am not clear with it.
Rachel
Now what is the difference by calling `A->foo() vs A::foo()`
Rachel
@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: http://en.wikipedia.org/wiki/Static_methods and the PHP docu: http://www.php.net/manual/en/language.oop5.static.php
Felix Kling
You can't overload a constructor in PHP. "Fatal error: Cannot redeclare A::__construct()"
Domenic
@Domenic Thanks for pointing that out. Another PHP annoyance.
Yacoby
@Yacoby: I can't make function static as I am using class properties to get some work done, is there any other way ?
Rachel
@Rachel In that case I recommend you look at Matt's answer. http://stackoverflow.com/questions/2555883/in-php-is-it-possible-to-create-an-instance-of-an-class-without-calling-classs/2555920#2555920
Yacoby
A: 

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');
knittl
Hmm, how this can be done, am really not sure. Would appreciate if you can give some more explanation about it.
Rachel
A: 

Yes, you can extend the class to override the constructor.

class no_construct extends SomeClass{
     function no_construct(){
     }
}
$myObj= new no_construct();

This will make an object of SomeClass without calling the constructor.

Rook
I am not supposed to extend the class.
Rachel
@Rachel: But you can change the class?
Felix Kling
+4  A: 

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
    }
}
Matt Huggins
Or, as others have pointed out, a static method may best suit your needs depending on what you're trying to do.
Matt Huggins
+1 for extending the class. Maybe it is a class of a third party library that should not be changed...
Felix Kling
+1 for the good alternative solutions.
Yacoby
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.
keithjgrant
+2  A: 

This is indeed possible.

Modified from from PHPUnit_Framework_MockObject_Generator.php

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.

Gordon
This is very hard to understand. Can you add some explanation to it.
Rachel
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.
Charles
@Rachel @Charles did a good job summing it up already, but see my detailed explanation as well.
Gordon