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

Rac*_*hel 16 php oop

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

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

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

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

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

Pet*_*ler 24

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

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

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

  • 使用PHP 5.4.0可以获得"newInstanceWithoutConstructor()"是没有价值的.它在任何版本的PHP 5.3或更低版本中都不可用. (3认同)

Gor*_*don 13

注意:以下解决方案适用于PHP 5.3及更低版本.从PHP 5.4开始,您也可以通过Reflection完成此操作,如本页其他地方所示.

这确实是可能的.

修改自 PHPUnit_Framework_MockObject_Generator

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

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


既然你要求解释:

当你序列化一个对象,你获取对象的字符串表示.例如

echo serialize(new StdClass) // gives O:8:"stdClass":0:{}
Run Code Online (Sandbox Code Playgroud)

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

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

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

'O:7:"MyClass":0:{}'
Run Code Online (Sandbox Code Playgroud)

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

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

这已经是它了.没什么太神奇的了.


Mat*_*ins 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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 或者,正如其他人指出的那样,静态方法可能最适合您的需求,具体取决于您想要执行的操作。 (2认同)
  • +1用于扩展课程。也许它是一个第三方库的类,不应该改变...... (2认同)