最灵活的(ευέλικτος!) PHP 依赖注入容器

1.0.0 2018-12-15 01:13 UTC

This package is auto-updated.

Last update: 2024-09-15 14:17:20 UTC


README

build coverage scrutinizer

evelikto-di

世界上最具灵活性的(ευέλικτος!) PHP 依赖注入容器。只需使用您需要的功能,无需运行时配置开销。

动机

尽管GitHub上有成百上千个PHP DI库,但没有任何一个提供零运行时成本容器配置。或者配置,可以被轻松分解成更小的块,或者可以被扩展用于不同的环境。Evelikto-DI的目标是结合性能、小巧的体积、最大灵活性以及易于使用的容器配置。

安装

Evelikto通过Composer/Packagist提供

"require": {
  "evelikto/di": "^1.0"
}

或者通过Composer CLI

composer require evelikto/di ^1.0 --prefer-distr

使用方法

类 \evelikto\di\AppContext 是DI容器的默认实现。基本用法是用构造函数实例化容器,传递应用程序配置给构造函数,然后将容器传递给框架,或者使用容器初始化框架。

$appContext = new \evelikto\di\AppContext(new AppConfig());

配置类必须遵循一些约定:1. 类中的每个方法都被视为一个工厂方法。2. 类中的每个常量都被视为一个配置值。3. 一个常量也可以代表一个接口名称别名(等于实现的具体类)。4. 一个方法也可以将一个接口映射到工厂方法。

// Every class can be a configuration class, there are no base classes
class AppConfig {
	// every constant in this class is considered to be a config value
	// these values are injectable by name: use $MY_APP_CONFIG_VALUE as argument
	const MY_APP_CONFIG_VALUE = 'config value';
	const ANOTHER_CONFIG_VALUE = 1.42;

	// this an alias for the interface \evelikto\mvc\Router
	// pointing to the concrete class \evelikto\mvc\router\ViewRouter
	// AppContext can now autowire ViewRouter if asked for a Router interface
	// function xxx(Router $router) will be injected with a ViewRouter instance.
	const EVELIKTO_MVC_ROUTER = '\\evelikto\\mvc\\router\\ViewRouter';

	// every method is considered to be a factory method
	// $pdo argument will be autowired by the container
	// container will register the new dependency
	// as 'databaseService' & '\app\core\DatabaseService'
	public function databaseService(\PDO $pdo) {
		$db = new \app\core\DatabaseService($pdo);
		// do some additional initialization
		return $db;
	}

	// Arrays can also be config values
	const MVC_VIEW_ROUTER_MAPPINGS = [
		'GET /' => '/index.php',
		'GET /about' => '/about/index.php',
	];

	public function eveliktoMvcRouter($MVC_VIEW_ROUTER_MAPPINGS) {
		return new ViewRouter($MVC_VIEW_ROUTER_MAPPINGS);
	}

	// this is another possibility to initialize interfaces
	// full interface name will be converted to camel-case method name
	// \evelikto\mvc\Router translates to
	public function eveliktoMvcRouter() {
		// inside the config file ask for config values via static::
		return new ViewRouter(static::MVC_VIEW_ROUTER_MAPPINGS);
	}
}

// in your index.php:
$appContext = new \evelikto\di\AppContext(new AppConfig());

这种方法的优点是配置的完全自由。它还允许您通过原生PHP方式以自然的方式定义多个配置。最好的消息是——您在CPU周期方面根本不需要为此付费!

// Extending base config class allows you to redefine values and factories
// for different environments.
class AppConfig {

	const PDO_HOSTNAME;
	const PDO_DATABASE;
	const PDO_USERNAME;
	const PDO_PASSWORD;

	/** @return \PDO */
	public function pdo() {
		$hostname = static::PDO_HOSTNAME;
		$database = static::PDO_DATABASE;
		$username = static::PDO_USERNAME;
		$password = static::PDO_PASSWORD;

		return new \PDO("mysql:host=$hostname;dbname=$database", $username, $password);
	}
}

class LocalConfig extends AppConfig {
	const PDO_HOSTNAME = 'local_host';
	const PDO_DATABASE = 'local_db';
	const PDO_USERNAME = 'local_dbo';
	const PDO_PASSWORD = 'local_pwd';
}

class CloudConfig extends AppConfig {
	const PDO_HOSTNAME = 'cloud_host';
	const PDO_DATABASE = 'cloud_db';
	const PDO_USERNAME = 'cloud_dbo';
	const PDO_PASSWORD = 'cloud_pwd';
}

// in your index.php:
$config = IS_CLOUD ? new CloudConfig : new LocalConfig;
$appContext = new \evelikto\di\AppContext($config);

// you may also put a number of config values into an interface
interface CloudDatabaseConsts {
	const PDO_HOSTNAME = 'cloud_host';
	const PDO_DATABASE = 'cloud_db';
	const PDO_USERNAME = 'cloud_dbo';
	const PDO_PASSWORD = 'cloud_pwd';
}

class CloudConfig extends AppConfig implements CloudDatabaseConsts {
	// other cloud values and factories
}

// or just put parts of your configuration into a trait
trait MvcConfig {
	public function eveliktoMvcRouter() {
		return new ViewRouter([
			'GET /' => '/index.php',
			'GET /about' => '/about/index.php',
		]);
	}
}

trait DatabaseConfig {
	// yes, you can autowire config values!
	public function pdo($PDO_CONNECTION, $PDO_USERNAME, $PDO_PASSWORD) {
		return new \PDO($PDO_CONNECTION, $PDO_USERNAME, $PDO_PASSWORD);
	}
}

// combine the traits in your config class to keep it clean and maintainable.
class AppConfig {
	uses MvcConfig, DatabaseConfig;
}

结论:“类作为配置”约定非常强大、快速且易于使用。