<commit_before>---
layout: post
title: Slim Framework - 3
categories: [Framework, PHP]
description: Dependency Injection & Inversion of Control
keywords: Framework, PHP
---
# DI和IoC

现代框架一般用到了`依赖注入``控制反转`的设计思想，了解这两种设计模式对理解框架的结构有很大帮助。

## DI

DI即`依赖注入`，那么什么是`依赖`呢？

`依赖`是一种关系，例如一种处理类Foo对象的类Baz，那么对于Baz而言，Foo就是它的`依赖`。

考虑以下两个代码段：

{% highlight php %}
<?php
class Foo {}

class Baz {
    protected $foo;

    public function __construct() {
        $this->foo = new Foo();
    }
}
{% endhighlight %}

{% highlight php %}
<?php
class Foo {}

class Baz {
    protected $foo;

    public function __construct(Foo $foo) {
        $this->foo = $foo;
    }
}
{% endhighlight %}

第一个代码段里面Foo的实例仅存在于Baz的实例中，两者之间是强依赖关系；而第二段代码中，将Foo的实例`注入`到Baz实例中，做到了Foo和Baz的解耦。

## IoC

IoC即`控制反转`。

传统的开发工作中，我们会对每一个业务对象进行构造，并且在程序中对所构造的对象进行管理和控制；IoC则意味着这一部分工作在IoC容器中进行，所有的业务对象由容器进行控制。

所谓`反转`，就是对传统设计中对`依赖`部分的`反转`；传统设计中，我们会主动控制依赖对象，而这里会由IoC容器进行创建和注入依赖。

虽然有**DI是IoC的一种实现方式**的说法，但是目前业界大概也都是只用这一种实现方式。

我觉得引自[开涛的博客-跟我学Spring3-IoC基础](http://jinnianshilongnian.iteye.com/blog/1413846)中的两幅图能够很明白地说明`反转`带来的改变。

![pic1](http://sishuok.com/forum/upload/2012/2/19/a02c1e3154ef4be3f15fb91275a26494__1.JPG)

![pic2](http://sishuok.com/forum/upload/2012/2/19/6fdf1048726cc2edcac4fca685f050ac__2.JPG)

# 参考资料

* http://blog.csdn.net/bestone0213/article/details/47424255
* http://www.jianshu.com/p/002542f9c854
* https://www.zhihu.com/question/25392984?sort=created
* http://jinnianshilongnian.iteye.com/blog/1413846<commit_msg>Change IoC&DI content to Code Clips<commit_after>---
layout: post
title: Slim Framework - 3
categories: [Framework, PHP]
description: Code clips.
keywords: Framework, PHP
---
# Code clips

## 容器和注入

Slim中依赖容器的注入主要有如下几种操作方式。

### 简单注入
{% highlight php %}
<?php
$app = new \Slim\Slim();
$app->foo = 'bar';
{% endhighlight %}

这种注入适合对简单对象的操作，如`number`/`string`/`array`等基本数据结构。

其实现首先使用`Slim.php`中的魔术方法`__set`，然后调用了依赖容器`Helper/Set.php`中的`set`方法，将数据存储到容器的`data`属性中。

### 资源定位器

如下的代码将Slim作为了一个资源的提供者，将资源构造的方法以闭包的形式注入到Slim的依赖容器中，然后以KV方式通过`Slim`的`__get`方法(依赖容器`Set`的`get`方法)进行获取。

注入的闭包在被请求时，会被调用并返回闭包的返回值。

{% highlight php %}
<?php
$app = new \Slim\Slim();

// 定义一个创建 UUID 的方法
$app->uuid = function(){
    return exec('uuidgen');
};

// 获取一个新的 UUID
$uuid_1 = $app->uuid;
$uuid_2 = $app->uuid;

// 断言两者不同
assert($uuid_1 !== $uuid_2);
{% endhighlight %}

这一部分的实现如下。
{% highlight php %}
<?php
namespace Slim\Helper;

class Set implements \ArrayAccess, \Countable, \IteratorAggregate
{
    // ...

    /**
     * Get data value with key
     * @param  string $key     The data key
     * @param  mixed  $default The value to return if data key does not exist
     * @return mixed           The data value, or the default value
     */
    public function get($key, $default = null)
    {
        if ($this->has($key)) {
            // 魔术方法`__invoke`
            $isInvokable = is_object($this->data[$this->normalizeKey($key)]) && method_exists($this->data[$this->normalizeKey($key)], '__invoke');
            // 传入$this，也就是容器Set自身
            return $isInvokable ? $this->data[$this->normalizeKey($key)]($this) : $this->data[$this->normalizeKey($key)];
        }

        return $default;
    }

    // ...
}
{% endhighlight %}

### 单例资源

这里的单例资源指的是每次请求是一样的资源。资源定位器一栏中生成UUID的代码示例如果调用两次`$app->uuid`会返回不同的UUID值，单例资源就是解决这个问题的。

{% highlight php %}
<?php
$app = new \Slim\Slim();

// 定义一个 stdClass
$app->container->singleton('std', function(){
    $obj = new \stdClass;
    $obj = microtime(true);
    return $obj;            
});

// 获取资源
$std_1 = $app->std;
$std_2 = $app->std;

// 断言两者是同一个实例
assert(true === (spl_object_hash($std_1) === spl_object_hash($std_2)));
{% endhighlight %}

它的实现是利用了PHP匿名函数中的`static`修饰符，实现如下。
{% highlight php %}
<?php
namespace Slim\Helper;

class Set implements \ArrayAccess, \Countable, \IteratorAggregate
{
    // ...

    /**
     * Ensure a value or object will remain globally unique
     * @param  string   $key   The value or object name
     * @param  \Closure $value The closure that defines the object
     * @return mixed
     */
    public function singleton($key, $value)
    {
        $this->set($key, function ($c) use ($value) {
            // 静态修饰符，执行结果存储到这里了
            static $object;

            if (null === $object) {
                $object = $value($c);
            }

            return $object;
        });
    }

    // ...
}
{% endhighlight %}


{'fraction_non_alphanumeric': 0.15714938328003655, 'fraction_numerical': 0.02512562814070352, 'mean_word_length': 3.5144329896907216, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 24, 'https://': 1, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3628613', 'n_tokens_mistral': 2188, 'n_tokens_neox': 2226, 'n_words': 287}