kilahm/ioc-factory-container

使用属性,将工厂编译成一个单独的类

v0.3.2 2015-03-17 20:25 UTC

This package is not auto-updated.

Last update: 2024-09-24 04:09:53 UTC


README

Join the chat at https://gitter.im/kilahm/IOCFactoryContainer Build Status HHVM Status

从用户定义的属性编译一个安全的IOC容器。

用法

此库包含一个可执行文件,它会扫描您的项目目录中的工厂,然后构建一个有效的Hack文件,将所有工厂作为单个类的公共实例方法进行别名。您的工厂方法必须只接受一个参数,即工厂容器。

工厂容器应在应用程序的引导过程中实例化一次。然后,您应该能够使用容器来实例化应用程序类并运行它。

使用属性标记工厂

以下是一个示例类及其标记的工厂函数。

<?hh // strict

final class A
{
  <<provides('myA')>>
  public static function factory(FactoryContainer $c) : this
  {
    return new static();
  }
}

属性名称是 provides,需要一个参数,该参数是工厂方法的别名。上述定义将编译为

...
  <<__Memoize>>
  public function getMyA() : /Foo
  {
    return $this->newMyA();
  }
  
  public function newMyA() : /Foo
  {
    return $this->runner->make(class_meth('/A', 'factory'));
  }
...

请注意,您可以通过多次调用 $factory->getMyA() 来检索相同的实例,但调用 $factory->makeMyA() 将始终返回一个新的实例。

运行工厂容器编译器

定义了一些工厂方法后,运行位于您的 vendor/bin 目录中的 findfactories 可执行文件。该可执行文件接受任意数量的参数,这些参数将被解释为基础目录以进行扫描。该可执行文件还将接受任意数量的 --exclude="..." 长选项,这些选项将被解释为要忽略的目录。

vendor/bin/findfactories src/ other/path --exclude="src/ignore” --exclude=”other/path/to/ignore"

上述命令(如果从项目目录运行)将递归地扫描 src/other/path/ 目录,但排除 src/ignoreother/path/to/ignore 目录及其子目录。生成的工厂容器文件将创建在项目根目录中,并将命名为 FactoryContainer.php。您可以通过使用 --install-path="dir/to/put/file" 选项提供安装 FactoryContainer.php 的路径。

命名空间

您可以使用命名空间和 use,编译器将扩展类名以包括其命名空间。

<?hh // strict

namespace Foo\Baz;

use Foo\Bar\IFoo;

final class Foo implements IFoo
{
  <<provides('realFoo')>>
  public static function fooFactory(FactoryContainer $c) : this
  {
    return new static();
  }
  
  ...
  
}
<?hh // strict

namespace Bar;

use Foo\Bar\IFoo;

final class FooBar implements IFoo
{
  <<provides('fooBar')>>
  public static function barFactory(FactoryContainer $c) : this
  {
    return new static();
  }
  
  ...
  
}

上述文件将编译成以下容器方法。

...
  <<__Memoize>>
  public function getRealFoo() : \Foo\Baz\Foo
  {
    return $this->newRealFoo();
  }
  
  public function newRealFoo() : \Foo\Baz\Foo
  {
    return $this->runner->make(class_meth('\Foo\Baz\Foo', 'fooFactory'));
  }
  
  <<__Memoize>>
  public function getFooBar() : \Bar\FooBar
  {
    return $this->newFooBar();
  }
  
  public function newFooBar() : \Bar\FooBar
  {
    return $this->runner->make(class_meth('\Bar\FooBar', 'barFactory'));
  }
...

上述示例中的所有工厂都不是非常有用的工厂。当某个特定类有许多依赖项并且您希望将实例化封装在单个方法中时,此工具将更有用。

<?hh // strict

namespace CoolStuff;

use A;
use Foo\Bar\IFoo;

<<__ConsistentConstruct>>
class Awesome
{
  <<provides('awesomeWithFoo')>>
  public static function makeWithRealFoo(FactoryContainer $c) : this
  {
    return new static($c->getRealFoo(), $c->getA());
  }
  
  <<provides('awesomeWithBar')>>
  public static function makeWithFooBar(FactoryContainer $c) : this
  {
    return new static($c->getFooBar(), $c->getA());
  }
  
  public function __construct(private IFoo $foo, private A $a)
  {
  }