Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/237.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
php,如何防止直接类实例化?_Php - Fatal编程技术网

php,如何防止直接类实例化?

php,如何防止直接类实例化?,php,Php,假设我有一门非常普通的课: class Money { public __construct($actualCountry) { $this->actualCountry = $actualCountry; } public function getValute() { return according to actual country } } 这个类需要创建一次,所以我有一个全局工厂: final cl

假设我有一门非常普通的课:

class Money
{
    public __construct($actualCountry)
    {
        $this->actualCountry = $actualCountry;
    }

    public function getValute()
    {
        return according to actual country
    }
}
这个类需要创建一次,所以我有一个全局工厂:

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = new Money(Config::getCountryCode());
        }
        return $this->money;
    }
}
无论何时我们想要使用:

Factory::getMoney()->
但今天我看到我的同事在尝试:

(new Money(Config::getCountryCode()))->getValute();
这显然是错误的,不需要多次出现。但是,类本身怎么能说“嘿,不要实例化我,使用工厂”

我不能将其设置为singleton,因为每次:

Money::getInstance(Config::getCountryCode());
这是毫无意义的


但真正的问题并不是因为它可能存在多重性——这是我从配置中通过当前国家的方式。什么是
Config
becames
GlobalConfig
?这就是为什么工厂要避免大量的参数传递(如果将有更多的参数传递给
Money
?)

如果我正确理解了你的意思,你需要的是

根据需要,抽象类不能直接初始化

定义为抽象的类不能实例化


如果我没有弄错你的意思,你需要的是

根据需要,抽象类不能直接初始化

定义为抽象的类不能实例化


无法完全阻止外部实例化,因为要使工厂正常工作,构造函数必须是可直接或间接公开访问的

您可以通过将构造函数设为私有并向类中添加静态工厂方法来隐藏构造函数:

class Money
{
    private function __construct($actualCountry)
    {
        $this->actualCountry = $actualCountry;
    }

    public static function fromFactory($actualCountry)
    {
        return new static($actualCountry);
    }

    public function getValute()
    {
        // return according to actual country
    }
}

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = Money::fromFactory(Config::getCountryCode());
        }
        return $this->money;
    }
}
或者,您可以更改构造函数以要求(键入的)第二个参数,这是所使用的工厂。但是,如果您的工厂使用静态方法,这将不起作用,如您的示例中所示:

class Money
{
    public function __construct($actualCountry, Factory $factory)
    {
        $this->actualCountry = $actualCountry;
    }

    public function getValue()
    {
        // return according to actual country
    }
}

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = new Money(Config::getCountryCode(), $this);
        }
        return $this->money;
    }
}

无法完全阻止外部实例化,因为要使工厂正常工作,构造函数必须是可直接或间接公开访问的

您可以通过将构造函数设为私有并向类中添加静态工厂方法来隐藏构造函数:

class Money
{
    private function __construct($actualCountry)
    {
        $this->actualCountry = $actualCountry;
    }

    public static function fromFactory($actualCountry)
    {
        return new static($actualCountry);
    }

    public function getValute()
    {
        // return according to actual country
    }
}

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = Money::fromFactory(Config::getCountryCode());
        }
        return $this->money;
    }
}
或者,您可以更改构造函数以要求(键入的)第二个参数,这是所使用的工厂。但是,如果您的工厂使用静态方法,这将不起作用,如您的示例中所示:

class Money
{
    public function __construct($actualCountry, Factory $factory)
    {
        $this->actualCountry = $actualCountry;
    }

    public function getValue()
    {
        // return according to actual country
    }
}

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = new Money(Config::getCountryCode(), $this);
        }
        return $this->money;
    }
}

我认为你应该重新考虑单身模式。它更符合你想要的逻辑

<?php
class Money
{
    private static $instance;

    private function __construct($countryCode)
    {
        #your code here...
    }

    /**
     * Do not include parameter for getInstance.
     * Make the call internally.
     * Now when you have to change Config to GlobalConfig will be painless.
     */
    public static function getInstance()
    {
        if (null === self::$instance) {
            return self::$instance = new Money(Config::getCountryCode());
        }

        return  self::$instance;
    }
}

我认为你应该重新考虑单身模式。它更符合你想要的逻辑

<?php
class Money
{
    private static $instance;

    private function __construct($countryCode)
    {
        #your code here...
    }

    /**
     * Do not include parameter for getInstance.
     * Make the call internally.
     * Now when you have to change Config to GlobalConfig will be painless.
     */
    public static function getInstance()
    {
        if (null === self::$instance) {
            return self::$instance = new Money(Config::getCountryCode());
        }

        return  self::$instance;
    }
}

您可以将构造函数设置为私有的或受保护的,以防止直接实例化。(参见其他提及单例模式的答案)

如果您不能/不想使用单例模式,那么您必须接受构造函数是公共的,或者使用一些闭包绑定魔法来绕过它

免责声明:这只是一个概念证明。我不会在任何生产代码中使用它。在PHP支持名称空间/类可见性/朋友类之前,没有很好的方法来实现这一点

class Factory
{
    private static $money;

    static function getMoney()
    {
        if (null === self::$money) {
            self::$money = self::createInstance('Money', [Config::getCountryCode()]);
        }

        return self::$money;
    }

    private static function createInstance($class, array $args)
    {   
        // bind a closure to the given class and call it
        return call_user_func(Closure::bind(function () use ($class, $args) {
            // create a new instance without calling the constructor
            $object = (new ReflectionClass($class))->newInstanceWithoutConstructor();

            // call the constructor manually from this context (which has access to it now)
            call_user_func_array([$object, '__construct'], $args);

            // return the constructed object
            return $object;
        }, null, $class));
    }
}
使用工厂:

var_dump(Factory::getMoney());
输出:

new Money();
对象(金钱)#3(1){ [“实际国家”:“货币”:私人]=> 字符串(10)“某些值” }

尝试直接实例化:

var_dump(Factory::getMoney());
输出:

new Money();
致命错误:从中的无效上下文调用private Money::_construct()。。。在线


您可以将构造函数设置为私有或受保护,以防止直接实例化。(参见其他提及单例模式的答案)

如果您不能/不想使用单例模式,那么您必须接受构造函数是公共的,或者使用一些闭包绑定魔法来绕过它

免责声明:这只是一个概念证明。我不会在任何生产代码中使用它。在PHP支持名称空间/类可见性/朋友类之前,没有很好的方法来实现这一点

class Factory
{
    private static $money;

    static function getMoney()
    {
        if (null === self::$money) {
            self::$money = self::createInstance('Money', [Config::getCountryCode()]);
        }

        return self::$money;
    }

    private static function createInstance($class, array $args)
    {   
        // bind a closure to the given class and call it
        return call_user_func(Closure::bind(function () use ($class, $args) {
            // create a new instance without calling the constructor
            $object = (new ReflectionClass($class))->newInstanceWithoutConstructor();

            // call the constructor manually from this context (which has access to it now)
            call_user_func_array([$object, '__construct'], $args);

            // return the constructed object
            return $object;
        }, null, $class));
    }
}
使用工厂:

var_dump(Factory::getMoney());
输出:

new Money();
对象(金钱)#3(1){ [“实际国家”:“货币”:私人]=> 字符串(10)“某些值” }

尝试直接实例化:

var_dump(Factory::getMoney());
输出:

new Money();
致命错误:从中的无效上下文调用private Money::_construct()。。。在线


不,你错了,那么即使是工厂也无法创建它。工厂无法“创建”它,但它将能够“扩展”它,这正是它应该被起诉的方式。我的$0.02:)不,你错了,那么即使是工厂也无法创建它。工厂无法“创建”它,但它将能够“扩展”它,这正是它应该被起诉的方式。我的$0.02:)我想。。。使构造函数私有化?你的工厂可以创造它,但其他任何东西都不能?我想。。。使构造函数私有化?你的工厂可以创造它,但其他任何东西都不能?