在PHP中,是否可以创建类的示例而不调用类的构造函数?

bakd9h0s  于 2023-02-03  发布在  PHP
关注(0)|答案(6)|浏览(156)

无论如何,是否可以创建PHP类的示例而不调用其构造函数?
我有一个类A,在创建它的示例时,我传递了一个文件,然后在类A的构造函数中打开了这个文件.
现在在类A中,有一个函数需要调用,但我不需要传递文件,所以不需要构造函数打开文件,因为没有传递文件。
所以我的问题是:有没有可能创建一个PHP类的示例而不调用它的构造函数?

    • 注意:**我不能使函数成为静态的,因为我在函数中使用了一些类属性。
13z8s7eq

13z8s7eq1#

在您的情况下,我建议考虑重新设计您的代码,这样您就不需要做这样的事情,但回答你的问题:是的,有可能.
您可以使用ReflectionClass及其在PHP 5.4中引入的newInstanceWithoutConstructor方法这样就很容易创建一个类的示例,而无需调用其构造函数:

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

bbmckpt72#

类的构造函数总是被调用的,不过有几种方法可以解决这个问题。
第一种方法是为构造函数中的参数提供默认值,并且仅在设置了这些参数时才对它们执行某些操作。例如:

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

gudnpqoy3#

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

这的确是可能的。
修改自PHPUnit_Framework_MockObject_Generator
请记住,像这样的代码在PHPUnit这样的框架中是很好的,但是如果你必须在你的产品代码中使用这样的代码,你可能会做一些非常奇怪的事情。
既然你要求解释:
当你serialize an Object的时候,你会得到一个对象的字符串表示。

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

O表示对象。8是类名的字符串长度。"stdClass"显然是类名。序列化的对象具有0属性集(* 更多内容稍后提供 *),由空大括号表示。:只是分隔符。
每个序列化的字符串都可以用unserialize函数重新创建为它的原始“live”值。这样做会绕过构造函数。就像Charles正确指出的,如果定义了神奇的方法__wakeup(),它就会被调用(就像序列化时调用__sleep()一样)。
在第3行中,您可以看到准备用于sprintf(第2行)的字符串。正如您所看到的,类名的字符串长度为%d,类名为%s。这是为了告诉sprintf,它应该使用第4行中传递给它的第一个参数作为数字,第二个参数作为字符串。因此,sprintf调用的结果为

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

您可以将第4行中出现的两个“MyClass”替换为所需的类名,以创建要示例化的类的序列化字符串,而无需调用控制器。
这个字符串然后被解序列化到第一行的MyClass示例中,绕过构造函数。解序列化的示例将拥有它的类的所有方法和所有属性。如果MyClass中有属性,这些属性将拥有它们的默认值,除非你给序列化的伪字符串添加不同的值。
就这样了。没什么特别的。

xpcnnkqh

xpcnnkqh4#

将您需要的函数设置为static- alter类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->的代码,你不能使它成为静态的。

omtl5h9j

omtl5h9j5#

像这样的东西有用吗?

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();
  }
}
oiopk7p5

oiopk7p56#

你可以使方法成为静态的,并且从类上下文而不是对象上下文调用它。
在代码中,它看起来如下所示:

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

A::func('test');

相关问题