Laravel 学习心得

来源:互联网 发布:电脑的记事软件 编辑:程序博客网 时间:2024/06/07 03:11

搭建Laravel

工欲善其事必先利其器,我们先搭建laravel,看看它的结构。


Laravel的核心设计模式

控制反转IoC):由内部依赖转化为外部依赖,调用者不在自身内部创建被调用者的实例,改为在外部创建。一般通过“接口(interface)”去约束外部依赖,让它满足我们的依赖条件。这个过程我们成为依赖注入(DI)。

//普通内部依赖class robot {    private $abilities = [];    public function __construct($a){        $abilities = $a ;    }    public function doSomething() {        foreach($abilities as $ability){            echo $ability;        }    }}//=======分割线===========//外部依赖实现的接口interface abilityInterface {    public function work(){}}//接口的具体实现class swimRobot implements abilityInterface {    public funtion work(){        echo 'swim';    }}class answerRobot implements abilityInterface {    public funtion work(){        echo 'answer';    }}//外部依赖(构造函数)class robot {    private $ability;    public function __construct(abilityInterface $ability){        $this->ability =  $ability;    }    public function doSomething(){        $this->ability->work();    }}$robot_swim = new robot(new swimRobot());$robot_answer = new robot(new answerRobot());

通过控制反转,我们可以根据业务需求去制造不同功能的类,只需要在类外部修改代码就可以,这个类实现我们约定的接口就可以。

laravel的核心是一个IoC容器。所谓的容器就是一个可以动态添加依赖的类。

//简单的“IoC容器“”class IocContainer {    private $classes_dependencies = [];    public function bind($class, $dependency){        $this->classes_dependencies[$class] = $dependency;    }    public function initialize($class, $parameters = []){        if(isset($this->classes_dependencies[$class])){            return call_user_func_array($this->classes_dependencies[$class], $parameters);         }    }}

服务提供者(Service Provider): 我们了解了IoC容器的概念之后,知道要声明服务类(一个提供服务的类,我们称为服务类),那必须在IoC容器中注册,在控制器中就可以直接找到该类并使用。我们不能把注册行为分散到每个类中,所以使用服务提供者来帮我们实现这个注册的动作。同时也便于管理。Laravel中使用配置文件去配置服务提供者,然后使用服务提供者去向IoC容器去注册服务类。

<?php//为了示例声明了服务类的契约。namespace App\Contracts;interface MessageContract{    public function send($m);}
<?php//定义一个提供服务的类namespace App\Services;use App\Contracts\MessageContract;class MessageService implements MessageContract {    public function send($m){        echo "send message: ".$m;    }}

定义完这个消息类之后,我们需要将它注册。需要一个对应的服务提供者。可以使用下面的命令:

php artisan make:provider MessageServiceProvider
<?php//这是生成的服务提供者。namespace App\Providers;use Illuminate\Support\ServiceProvider;use App\Services\MessageService ; //我们刚刚定义的服务类class MessageServiceProvider extends ServiceProvider{    /**     * Bootstrap the application services.     *     * @return void     */    public function boot()    {        //    }    /**     * Register the application services.     *     * @return void     * @author LaravelAcademy.org     */    public function register()    {        //使用singleton绑定单例        $this->app->singleton('MyMessage',function(){            return new MessageService();        });        //或者使用bind绑定实例到接口以便依赖注入        /*        $this->app->bind('App\Contracts\MessageContract',function(){            return new MessageService();        });        */    }}

可以看到一个服务提供者有两个方法,boot跟register。当我们确定没有使用其他尚未加载的服务类时,我们写在register方法中,并且只绑定事物到服务容器,不做其他事情。当我们使用到了尚未加载的服务类时,我们写在boot中,该方法是在所有服务提供者被注册以后才会被调用。例如:

 public function boot()    {        //这里使用了其他未被加载的服务类         view()->composer('view', function () {            //        });    }

如果我们确定当前服务只需要一个实例,我们可以使用 singleton 去注册,我们使用到该服务的时候都是取这一个实例,如果我们需要动态修改(依赖注入)这个服务类,我们使用bind方法。两者取一。底层的框架singleton的实现代码:

...public function singleton($abstract, $concrete = null){    $this->bind($abstract, $concrete, true);}...

我们需要去向容器注册我们的服务提供者,追加该类到配置文件config/app.php的providers数组中即可:

'providers' => [    //其他服务提供者    App\Providers\MessageServiceProvider::class,],

创建一个test控制器:

 php artisan make:controller Test/TestController

简单设置路由(app\Http\routes.php):

Route::resource('test','Test\TestController');
<?phpnamespace App\Http\Controllers\Test;use Illuminate\Http\Request;use App\Http\Requests;use App\Http\Controllers\Controller;class TestController extends Controller{    /**     * Display a listing of the resource.     *     * @return \Illuminate\Http\Response     */    public function index()    {         //直接使用容器调用        app('MyMessage')->send('testing');    }    ...//其他控制器动作}

访问你本地的路由就可以看到结果(public作为根目录)。我们回顾一下声明服务的过程,首先声明一个提供服务的类(可以选择使用契约),声明一个对应的服务提供者,将它注册到IoC容器,接着注册一下该服务提供者。在IoC容器看来,就是先获取了服务提供者数组,然后注册他们提供的服务类。如果我们需要修改这个服务类,只需要修改它本身就可以,删除就取消注册对应的服务提供者,控制器中的代码不用去关心这个服务类。

门面模式 (Facade):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。门面模式又称为外观模式,它是一种对象结构型模式。

门面模式的概念看起来挺复杂,我们结合生活中的例子来阐述。
场景:下班回家,你首先要开门,开灯,然后开煮水器,开热水器,开空调。我们抽象你的家为一个系统,那么你(用户)跟这个系统的交互是很繁杂的。门面模式为你提供一个家用机器人,只需要告诉这个机器人我要回家了,它会帮你把上面的动作都做好,你(用户)根本感觉不到家里的电器是怎么开的。在这个例子中,机器人就相当于系统的“门面”或者“外观”。

在 Laravel 应用中,该机制原理由 Facade 类实现。Laravel 自带的门面,以及我们创建的自定义门面,都会继承自 Illuminate\Support\Facades\Facade 基类。门面类只需要实现一个方法:getFacadeAccessor。正是 getFacadeAccessor 方法定义了从容器中解析什么,然后Facade 基类使用魔术方法 __callStatic() 从你的门面中调用解析对象。下面是实例:

创建一个出租屋类:

<?phpnamespace App\Facades;class RentHouse{    public function comeHome()    {        echo "turn on the lights <br>";        echo "turn on the TV <br>";        echo "shower <br>";    }}

创建一个出租屋的机器人(门面):

<?phpnamespace App\Facades;use Illuminate\Support\Facades\Facade;class RentHouseRobot extends Facade{    protected static function getFacadeAccessor()    {        //相当于告诉容器 该类是哪个类的门面        return 'RentHouse';    }}

接下来我们要在服务提供者中绑定Test类到服务容器,新建一个provider:

<?phpnamespace App\Providers;use Illuminate\Support\ServiceProvider;use App\Facades\RentHouse;class RentHouseProvider extends ServiceProvider{    /**     * Bootstrap the application services.     *     * @return void     */    public function boot()    {    }    /**     * Register the application services.     *     * @return void     */    public function register()    {        $this->app->singleton('RentHouse',function(){            return new RentHouse();        });    }}

再然后需要到配置文件config/app.php中注册门面类别名以及RentHouseProvider:

'providers' => [    //其他服务提供者    App\Providers\RentHouseProvider::class,],'aliases' => [    ...//其他门面类别名映射    'RentHouseRobot' => App\Facades\RentHouseRobot::class,],

最后控制器再调用:

<?phpnamespace App\Http\Controllers\Test;use Illuminate\Http\Request;use App\Http\Requests;//这里需要引入这个门面use RentHouseRobot;use App\Http\Controllers\Controller;class TestController extends Controller{    /**     * Display a listing of the resource.     *     * @return Response     */    public function index()    {       //app('MyMessage')->send('testing');       RentHouseRobot::comeHome();    }    ...//其他方法}

同上访问你的路由就可以看到结果了。

仓储模式(repository):Repository 是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository 是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。

又是文绉绉的定义。让我们举这样一个例子,有一个有钱人,他有农场,牧场,渔场。这几个仓库的类型都是不一样的,我们(领域层)去操作不同的仓库是痛苦的,所以需要一个仓库管理员,他负责帮我们存储,取出,扔掉,只要他会这些技能他就能做我们的仓库管理员。同时我们定义一个类别的货物成对象,比如渔场的产品,有名字,鱼类,生产日期等,我们跟仓库管理员打交道只需要获取这个对象去处理就可以了,其他的我们不用管。实例如下:

我们先定义我们货物的类,假设货物具有产地,ID,生成日期,过期时间,名称等属性。

<?phpnamespace App\Repositories\Farm;//在仓储模式中,我们定义货物的类只需要属性跟getter,setter。class Product{    private $id;    private $name;    private $created;    private $source;    private $expired;    public function setId($id)    {        $this->id = $id;    }    public function getId()    {        return $this->id;    }    public function setName($name)    {        $this->name = $name;    }    public function getName()    {        return $this->name;    }    public function setCreated($created)    {        $this->created = $created;    }    public function getCreated()    {        return $this->created;    }    public function setSource($source)    {        $this->source = $source;    }    public function getSource()    {        return $this->source;    }    public function setExpired($expired)    {        $this->expired = $expired;    }    public function getExpired()    {        return $this->expired;    }}

接下来我们定义一个仓库应该具有的方法(数据访问层):

<?phpnamespace App\Repositories\Farm;interface Storage{    //制定一些规则    public function persist($data);    public function retrieve($id);    public function delete($id);}

通过实现上面的接口,我们可以定义一个或几个仓库管理员。在实际应用中,我们或许会对货物划分不同的规则,但是货物类本身是不会改变的,规则就交给仓库管理员接口去管理。

<?phpnamespace App\Repositories\Farm;use App\Repositories\Farm\Storage;//一个仓库管理员的实现class FarmStorage implements Storage {    private $data;    private $lastId;    public function __construct()    {        $this->data = array();        $this->lastId = 0;    }    public function persist($data)    {        $this->data[++$this->lastId] = $data;        return $this->lastId;    }    public function retrieve($id)    {        return isset($this->data[$id]) ? $this->data[$id] : null;    }    public function delete($id)    {        if (!isset($this->data[$id])) {            return false;        }        $this->data[$id] = null;        unset($this->data[$id]);        return true;    }}
原创粉丝点击