haijin/instantiator

一个使用简单DSL创建和获取对象实例的库。

此包的官方仓库似乎已丢失,因此该包已被冻结。

v2.0.0 2019-02-22 00:51 UTC

This package is auto-updated.

Last update: 2022-12-28 00:32:54 UTC


README

一个使用简单DSL创建和获取对象实例的库。

Latest Stable Version Latest Unstable Version Build Status License

版本 2.0.0

如果您非常喜欢它,可以通过资助其开发来做出贡献。

目录

  1. 安装
  2. 使用
    1. 创建新实例
    2. 访问单例
    3. 覆盖当前进程中的实例化器
    4. 使用单例覆盖新的实例化器
  3. 运行测试

安装

将此库包含到您的项目 composer.json 文件中

{
    ...

    "require": {
        ...
        "haijin/instantiator": "^2.0",
        ...
    },

    ...
}

使用

创建新实例

不要使用 new 创建对象,而是使用

use  Haijin\Instantiator\Create;

$object = Create::a( Sample_Class::class )->with( 1, 2, 3 );

您也可以不使用DSL,通过以下方式避免对象创建和一些函数调用

use  Haijin\Instantiator\Create;

$object = Create::object( Sample_Class::class, 1, 2, 3 );

或者

use  Haijin\Instantiator\Create;

$object = Global_Factory::new( Sample_Class::class, 1, 2, 3 );

但我们强烈建议始终使用DSL。使用DSL背后的哲学是优化表达性、可读性和简单性。代码优化应该在基准测试了实际应用的真实使用场景之后进行。

访问单例

使用以下方法创建任何类的单例实例

use  Haijin\Instantiator\Singleton;

Singleton::create( Sample::class, new Sample( 1, 2, 3 ) );

并通过以下方式访问它们

use  Haijin\Instantiator\Singleton;

$object = Singleton::of( Sample::class );

// or

$object = Global_Factory::singleton_of( Sample::class );

单例也可以命名

use  Haijin\Instantiator\Singleton;

Singleton::create( 's', new Sample( 1, 2, 3 ) );

$object = Singleton::of( 's' );

覆盖当前进程中的实例化器

可以使用以下方法在当前进程的作用域内临时更改类的实例化器和单例

use  Haijin\Instantiator\Global_Factory;
use  Haijin\Instantiator\Create;
use  Haijin\Instantiator\Singleton;

$object = Create::a( Sample::class )->with( 1, 2, 3 );

( $object instanceof Sample ) === true;

Singleton::create( 's', new Sample( 1, 2, 3 ) );


$singleton = Singleton::of( 's' );

( $singleton instanceof Sample ) === true;

Global_Factory::with_factory_do( function($factory) 
{
    // change the instantiators within the scope of this closure

    $factory->set( Sample::class, Different_Sample::class );

    Singleton::create( 's', new Different_Sample( 1, 2, 3 ) );


    $object = Create::a( Sample::class )->with( 1, 2, 3 );

    ( $object instanceof Different_Sample ) === true;


    $singleton = Singleton::of( 's' );

    ( $singleton instanceof Different_Sample ) === true;

}, $this);


// restores the previous instantiators

( $object instanceof Sample ) === true;

Singleton::create( 's', new Sample( 1, 2, 3 ) );


$singleton = Singleton::of( 's' );

( $singleton instanceof Sample ) === true;

这意味着两个不同的进程可以同时根据需要覆盖实例化器和单例。例如,一个进程中的实例化器类 Database 可能被重写为 MysqlDatabse,而另一个进程中的 Database 类可能被重写为 PostgresDatabase,但使用 Database 类的代码可以安全地共享并实例化数据库对象,而无需意识到它,也无需传递工厂或容器对象。

use  Haijin\Instantiator\Global_Factory;
use  Haijin\Instantiator\Singleton;

public function access_data_in_mysql($connection_string)
{
    Global_Factory::with_factory_do( function($factory) use($connection_string)
    {
        Singleton::create( Database::class, new MysqlDatabase( $connection_string ) );

        $this->process_data();

    }, $this);
}

public function access_data_in_postgres($connection_string)
{
    Global_Factory::with_factory_do( function($factory) use($connection_string)
    {
        Singleton::create( Database::class, new PostgresDatabase( $connection_string ) );

        $this->process_data();

    }, $this);
}

public function process_data()
{
    $db = Singleton::of( Database::class );

    /// etc ...
}

使用单例覆盖新的实例化器

前面的例子有一个问题,即使用数据库的代码需要知道它是一个单例。这对于一个库来说是一个很大的假设。

相反,它可以实例化数据库,每次都创建一个新的实例,但使用它的代码可以覆盖新实例的创建,使用单例

use  Haijin\Instantiator\Global_Factory;
use  Haijin\Instantiator\Singleton;

public function access_data_in_mysql($connection_string)
{
    Global_Factory::with_factory_do( function($factory) use($connection_string)
    {
        $factory->new_as_singleton( Database::class, new MysqlDatabase( $connection_string ) );

        $this->process_data();

    }, $this);    
}

public function access_data_in_postgres($connection_string)
{
    Global_Factory::with_factory_do( function($factory) use($connection_string)
    {
        $factory->new_as_singleton( Database::class, new PostgresDatabase( $connection_string ) );

        $this->process_data();

    }, $this);    
}

public function process_data()
{
    $db = Create::a( Database::class )->with();

    /// etc ...
}

这样做允许底层代码(如第三方库)不假设对象是单例,而最顶层的代码(如应用程序)可以根据其需要将其设置为单例或非单例,而库无需知道这一点。

仅当单例没有副作用时,才应该覆盖实例的创建。例如,如果单例不会从一个函数保持共享状态到另一个函数。

运行测试

composer specs