Php 如何防止使用0参数进行构造?

Php 如何防止使用0参数进行构造?,php,Php,考虑以下类别: class Asterisk implements IExpr { /** @var string */ protected $databaseName; /** @var string */ protected $tableName; function __construct($database=null, $table=null) { switch(func_num_args()) { case

考虑以下类别:

class Asterisk implements IExpr {
    /** @var string */
    protected $databaseName;
    /** @var string */
    protected $tableName;

    function __construct($database=null, $table=null) {
        switch(func_num_args()) {
            case 0:
                $this->databaseName = null;
                $this->tableName = null;
                break;
            case 1:
                $this->databaseName = null;
                $this->tableName = $database;
                break;
            case 2:
                $this->databaseName = $database;
                $this->tableName = $table;
                break;
            default:
                throw new \BadMethodCallException("Expected 0-2 args");
        }
    }

    public static function value() {
        static $value;
        if(!$value) $value = new self;
        return $value;
    }
}
我想阻止开发人员使用
0
args构建
Asterisk
的新实例,而不使用
Asterisk::value()
方法。0-arg的情况很特殊,我只需要一个实例


那么我该怎么做呢?

那么您需要定义自己的构造函数。如果用户传递了错误数量的参数,PHP仍然会创建对象的实例。使构造函数私有,并从静态方法实例化。通过将构造函数设置为私有,API用户将无法使用公共API默认构造函数

private function __construct($database=null, $table=null) {
    // ...
}


public static function newInstance() {
    if(func_num_args() > 0) {
        return new self(func_get_args());
    } else {
        throw new \BadMethodCallException("Expected 0-2 args");
    }
}


Asterisk::newInstance() // throws BadMethodCallException()

$ast = Asterisk::newInstance(1, 2); // works, returns an instance of Asterisk.

为了完整性起见,我们可以通过另一种方法进行一些修改:

class Asterisk implements IField {
    /** @var string */
    protected $databaseName;
    /** @var string */
    protected $tableName;

    /**
     * @param string $database Database name, or table name if 2nd arg is omitted
     * @param string $table Table name
     */
    function __construct($database, $table=null) {
        switch(func_num_args()) {
            case 1:
                if($database === null) throw new \BadMethodCallException("Table cannot be null");
                $this->databaseName = null;
                $this->tableName = $database;
                break;
            case 2:
                if($database === null || $table === null) throw new \BadMethodCallException("Database or table cannot be null");
                $this->databaseName = $database;
                $this->tableName = $table;
                break;
            default:
                throw new \BadMethodCallException("Expected 1 or 2 args");
        }
    }


    public static function value() { 
        static $value;
        if(!$value) $value = (new \ReflectionClass(self::class))->newInstanceWithoutConstructor();
        return $value;
    }
}

我们可以创建该类的新实例,而无需调用构造函数

好建议。这比我想象的解决方案更简洁,但如果仅这一个类使用“替代”构造函数,则会使我的API有点不一致。是的,对于代码的新用户来说,使用这种独特的新方法构造对象可能会显得很奇怪。因为在PHP中,无法同时使用私有(0参数)和公共(多参数)构造函数,这似乎是最干净的解决方案。每当遇到这样的问题时,你需要问自己一件事,那就是为什么会出现这种情况。是否有更常见的设计可以解决您的潜在问题?“特殊”实例真的是同一种对象吗?或者应该管理对象的所有实例(建议使用静态工厂,如下面的答案所示)。或者这些空值是其他默认值的伪装?@IMSoP是的,它是同一种对象。问题有两个方面:(1)效率;我不鼓励用户创建许多不可变对象的实例,类似于Java的小整数装箱(2)。只有一种情况下,0-arg版本会产生警告,但在其他情况下,它们的行为相同。将其拆分为第二类将产生比我认为消除的复杂性更大的复杂性。这就是说,我想我可以通过添加另一个方法而不是依赖引用相等来发现这种特殊情况。如果效率参数适用于所有变体,那么私有构造函数+静态工厂肯定是适合的模型,因为这样你也可以优化其他常见情况:
static$instances。。。返回$instances[$database][$table]