在PHP中,是否可以在不调用类的构造函数的情况下创建类的实例?

时间:2010-03-31 19:29:16

标签: php oop

无论如何,是否可以在不调用其构造函数的情况下创建php类的实例?

我有A类,在创建它的实例时传递文件,在A类的构造函数中打开文件。

现在在A类中,有一些我需要调用的函数但不需要传递文件,所以不需要使用打开文件的构造函数,因为我没有传递文件。

所以我的问题是,是否可以通过任何方式创建PHP类的实例而无需调用其构造函数?

注意我不能使函数静态,因为我正在使用函数中的一些类属性。

5 个答案:

答案 0 :(得分:22)

在你的情况下,我建议考虑重新设计你的代码,这样你就不需要做这样的事情,而是回答你的问题:是的,有可能

您可以使用ReflectionClass及其在 PHP 5.4中引入的方法newInstanceWithoutConstructor 然后,在不调用其构造函数的情况下创建类的实例非常容易:

$reflection = new ReflectionClass("ClassName");
$instance = $reflection->newInstanceWithoutConstructor(); //That's it!

答案 1 :(得分:13)

注意:以下解决方案适用于PHP 5.3及更低版本。从PHP 5.4开始,您还可以do it via Reflection as shown elsewhere on this page

这确实是可能的。

PHPUnit_Framework_MockObject_Generator修改

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

请记住,这样的代码在PHPUnit这样的框架中都是好的和合理的。但是如果你的生产代码中必须有这样的代码,你可能会做一些非常奇怪的事情。


因为您要求解释:

当你serialize an Object获得对象的字符串表示时。例如

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

O表示对象。 8是类名的字符串长度。 "stdClass"显然是班级名称。序列化对象设置了0属性(以后更多),由空花括号表示。 :只是分隔符。

可以使用unserialize函数将每个序列化字符串重新创建为其原始“实时”值。这样做会绕过构造函数。就像Charles正确指出的那样magic method __wakeup()如果被定义就会被调用(就像序列化时会调用__sleep()一样)。

在第3行中,您会看到一个准备与sprintf一起使用的字符串(第2行)。如您所见,类名称的字符串长度为%d,类名称为%s。这是告诉sprintf它应该使用第4行传递给它的第一个参数作为数字而第二个参数作为字符串使用。因此,sprintf调用的结果是

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

您可以将第4行中出现的“MyClass”替换为您想要的类名,以创建要实例化的类的序列化字符串,而无需调用控制器。

然后,将此字符串反序列化为第1行中的MyClass实例,绕过构造函数。反序列化的实例将包含它的类的所有方法以及任何属性。如果MyClass中有属性,则这些属性将具有默认值,除非您向序列化的虚拟字符串添加不同的值。

而且已经是这样了。没什么太神奇的了。

答案 2 :(得分:12)

将始终调用类构造函数。不过,有几种方法可以解决这个问题。

第一种方法是在构造函数中为参数提供默认值,并且只有在这些参数设置时才对这些参数执行某些操作。例如:

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
    }
}

另一个选择是扩展您的类,使子类的构造函数不调用父类的构造函数。

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
    }
}

答案 3 :(得分:2)

制作所需功能static不是更好   - 改变类A,使其具有另一个不带任何结果的构造函数


如果某个类的函数不能访问类中的任何非静态属性或函数,则可以将其设置为静态。

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

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

然后可以在不必构造类

的情况下调用它
//the constructor will not be called as we haven't created an instance of A
A::foo();

静态和非静态函数之间的区别在于静态函数不能访问也是静态函数的类属性。因此,如果在foo()中您有任何使用$this->的代码,则无法将其设为静态。

答案 4 :(得分:-1)

你可以使方法静态,并从类上下文而不是对象上下文中调用它。

代码中的

看起来像这样:

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

A::func('test');