## 实例容器
框架集成了 `Pimple\Container` 容器,并且预注册了部分实例。`app` 方法目前只实现了单例。
使用实例:
```php
app('app');
app('redis');
app('logger');
app('event');
```
app 方法:
```php
if (! function_exists('app')) {
/**
* Get the available container instance.
*
* @param string $abstract
* @param array $parameters
* @return mixed|\Mod\Fend\Application
*/
function app($abstract = null, array $parameters = [])
{
if (is_null($abstract)) {
return Application::getInstance();
}
return Application::getInstance()->make($abstract, $parameters);
}
}
```
应用实例代码,路径:app/Fend/Application.php
```php
<?php
namespace App\Fend;
use Closure;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use InvalidArgumentException;
use Pimple\Container as PimpleContainer;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\ContextProvider\CliContextProvider;
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Dumper\ServerDumper;
use Symfony\Component\VarDumper\VarDumper;
class Application extends PimpleContainer
{
/**
* The current globally available container (if any).
*
* @var static
*/
protected static $instance;
/**
* The loaded service providers.
*
* @var array
*/
protected $loadedProviders = [];
/**
* Current version
*
* @var string
*/
const VERSION = '2.0.0';
/**
* Create new container
*
* @param array $values The parameters or objects.
*/
public function __construct(array $values = [])
{
parent::__construct($values);
$this->bootstrapContainer();
}
/**
* Bootstrap the application container.
*
* @return void
*/
protected function bootstrapContainer()
{
static::setInstance($this);
$this['app'] = $this;
$this[self::class] = $this;
//$this->bootDumpServer();
$this->registerEventBindings();
$this->registerRedisBindings();
$this->registerLoggerBindings();
}
/**
* Set the shared instance of the application.
*
* @param $container
* @return Application
*/
public static function setInstance($container = null)
{
return static::$instance = $container;
}
/**
* Set the globally available instance of the application.
*
* @return static
*/
public static function getInstance()
{
if (is_null(static::$instance)) {
throw new InvalidArgumentException('Expected a Application');
}
return static::$instance;
}
/**
* 绑定 DumpServer
*/
public function bootDumpServer()
{
$cloner = new VarCloner();
$fallbackDumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper() : new HtmlDumper();
$dumper = new ServerDumper('tcp://127.0.0.1:9912', $fallbackDumper, [
'cli' => new CliContextProvider(),
'source' => new SourceContextProvider(),
]);
VarDumper::setHandler(function ($var) use ($cloner, $dumper) {
$dumper->dump($cloner->cloneVar($var));
});
}
/**
* Register container bindings for the application.
*
* @return void
*/
protected function registerEventBindings()
{
$this->bind('events', function(){
return new EventDispatcher();
});
}
/**
* Register container bindings for the application.
*
* @return void
*/
protected function registerRedisBindings()
{
$this->bind('redis', function(){
return (new \Fend_Cache_Redis())->mc;
});
}
/**
* Register container bindings for the application.
*
* @return void
*/
protected function registerLoggerBindings()
{
$path = date('Ym/');
$backtraceCallable = function($record) {
$record['extra'] = array_slice(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS),3);
return $record;
};
$this->makeBindLogger('', $path, $backtraceCallable);
$this->makeBindLogger('.pay', $path, $backtraceCallable);
$this->makeBindLogger('.order', $path, $backtraceCallable);
$this->makeBindLogger('.power', $path, $backtraceCallable);
$this->makeBindLogger('.goods', $path, $backtraceCallable);
$this->makeBindLogger('.packet', $path, $backtraceCallable);
$this->makeBindLogger('.notify', $path, $backtraceCallable);
$this->makeBindLogger('.studycard', $path, $backtraceCallable);
$this->makeBindLogger('.rechargecard', $path, $backtraceCallable);
$this->makeBindLogger('.activity', $path, $backtraceCallable);
}
/**
* 创建并绑定日志服务
*
* @param $name
* @param $path
* @param $backtraceCallable
*/
public function makeBindLogger($name, $path, $backtraceCallable)
{
$this->bind('logger'.$name, function() use ($name, $path, $backtraceCallable){
$logger = new Logger($name ? substr($name, 1) : 'app');
$logger->pushHandler(new StreamHandler(FD_SYSROOT.'data/logs/'.$path.'app'.$name.'.log', \Monolog\Logger::DEBUG));
$logger->pushProcessor($backtraceCallable);
return $logger;
});
}
/**
* Get the version number of the application.
*
* @return string
*/
public function version()
{
return static::VERSION;
}
/**
* Register a service provider with the application.
*
* @param $provider
*/
public function registerProvider($provider)
{
if (! $provider instanceof ServiceProvider) {
$provider = new $provider($this);
}
if (array_key_exists($providerName = get_class($provider), $this->loadedProviders)) {
return;
}
$this->loadedProviders[$providerName] = $provider;
if (method_exists($provider, 'register')) {
$provider->register();
}
if (method_exists($provider, 'boot')) {
$provider->boot();
}
}
/**
* Resolve the given type from the container.
*
* @param string $abstract
* @param array $parameters
* @return mixed
*/
public function make($abstract = '', $parameters = [])
{
if( !$this->has($abstract) ){
$this[$abstract] = function ($container) use ($abstract, $parameters) {
$instance = empty($parameters) ? new $abstract : new $abstract(...$parameters);
if (method_exists($instance, 'setContainer')) {
$instance->setContainer($container);
}
if (method_exists($instance, 'initialize')) {
$instance->initialize();
}
return $instance;
};
}
return $this->get($abstract);
}
/**
* Register a binding with the container.
*
* @param string $abstract
* @param null $concrete
* @return $this|void
*/
public function bind($abstract, $concrete = null)
{
if ( !$concrete instanceof Closure ) {
return;
}
$this[$abstract] = $concrete;
return $this;
}
/********************************************************************************
* Magic methods for convenience
*******************************************************************************/
public function __get($name)
{
return $this->get($name);
}
public function __isset($name)
{
return $this->has($name);
}
/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* @param string $id Identifier of the entry to look for.
*
* @return boolean
*/
public function has($id)
{
return $this->offsetExists($id);
}
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @return mixed
*/
public function get($id)
{
if (!$this->offsetExists($id)) {
throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
}
return $this->offsetGet($id);
}
}
```