我在这里有点迷失,因为我想在Java中做一些非常简单但在PHP中看起来有点复杂的东西。
我们正在为我们的产品和Java构建SDK,我们有一个类,不能(!)由用户(即编码器)实例化,因为它有关于它的完整性的若干约束。所以我们在“XFactory”中构建了一个嵌套类“X”,你将通过调用XFactory.buildMeMyX()得到一个X实例; - 容易......
现在PHP根本不支持嵌套类,我想知道如何在这里应用相同的类。在Java中,X的构造函数是隐藏的(私有),因此只有XFactory可以调用它。
在PHP中,看起来我必须公开__construct()并将嵌套的类X移出XFactory。因此,用户将能够在没有Factory的情况下创建实例。
现在 - 我可以将工厂功能移到X本身并移动所有东西,但这会破坏SDK的设计。毕竟,有没有一种有用的方法在PHP中做这些事情?
答案 0 :(得分:3)
对于 PHP 5.x ,您已经描述了您的选项,根本没有私有/受保护的类或内部类,因此没有其他方法可以限制实例化。
仍然没有嵌套类(虽然我们将来可能会看到它们,请参阅:https://stackoverflow.com/a/31454435/664108),但您可以实例化anonymous class并仅向消费者提供如下所示的接口:< / p>
class XFactory
{
public function buildMeMyX()
{
return new class() implements XInterface {
public function doWhatEverAnXCanDo()
{
// X X X
}
// ...
};
}
}
interface XInterface
{
function doWhatEverAnXCanDo();
}
答案 1 :(得分:1)
还没有本地方法可以这样做。但是,如果你真的想要强制执行&#34;你的班级只是从你的工厂班级创建的,有一点&#34; hackish&#34;通过异步类来限制实例化的方法。
class X
{
function __construct()
{
new Y();
}
}
class Y
{
function __construct()
{
$trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
if (!isset($trace[1]['object']) || !($trace[1]['object'] instanceof X)) {
throw new \RuntimeException('This is a private class');
}
}
}
new X(); // All is fine
new Y(); // Exception
请注意,没有&#34;真实&#34;即使使用这种方法,保护类不被其他地方实例化的方法 - 它仍然可以通过绕过构造函数或仅修改源来通过反射来完成。
答案 2 :(得分:1)
正如其他人所说,目前在PHP中没有干净的方法来实现这种行为。在我看来,私有构造函数的唯一有效用例是实现工厂的类中的工厂。
每当你试图绕过那个用例时,它就会变得混乱。 没有人应该尝试发明巧妙的方法来绕过PHP的语言限制。
我只是为了证明确实可能而违反了这条规则。但请不要在生产中使用它,或者更好:在任何地方使用它。我将尝试为该建议找到一些防弹参数并在之后编辑答案。
<?php
class Dependency {}
class SomeClass {
protected $dep;
private function __construct(Dependency $dep)
{
$this->dep = $dep;
}
public function doSomething()
{
var_dump($this->dep);
echo "Doing Stuff and even having dependencies";
}
}
class SomeClassFactory {
public function buildSomeClass()
{
return $this->instantiateSomeClassWith(new Dependency);
}
protected function instantiateSomeClassWith()
{
$reflectionClass = new ReflectionClass('SomeClass');
$someClass = $reflectionClass->newInstanceWithoutConstructor();
$constructor = $reflectionClass->getConstructor();
$constructorClosure = $constructor->getClosure($someClass);
call_user_func_array($constructorClosure, func_get_args());
return $someClass;
}
}
$factory = new SomeClassFactory();
$someClass = $factory->buildSomeClass();
$someClass->doSomething();
?>
输出:object(Dependency)#2 (0) { } Doing Stuff and even having dependencies
理论很简单。将通过Factory构建的类的构造函数是私有的。我们在工厂中使用反射来创建类的实例而不调用构造函数。
一旦我们有了一个实例,我们抓住构造函数的闭包并通过call_user_func_array()
调用它。这样就可以像使用构造函数一样使用依赖注入。
正如我之前所说。那种方式是一种气味。通过创建一个对象而不调用它的构造函数,没有真正的方法来在创建时验证对象状态
这是一个概念证明,但概念很糟糕。