我们公司现在在用Laravel
开发项目,同时还增加了Biz
层和Repositories
层,来实现业务逻辑封装,反而model
里面什么代码都没有。
在Controller
里写代码的时候,尝尝困扰我的问题是如果复用Biz
对象,Repositories
对象和Model
对象。
以前用Yii
开发项目的时候,有一个工厂模式,所以调用Model
的时候,基本都不new
,都是字节用 XXX::model() 来调用的,一个对象被new一次就够了,能有效节省内存。
Controller代码:
$productModel = Product::model()->getList('xxxxxxxxx');
多简单,有没有?
Laravel
里,Model
好像没有工厂,要调用,都需要实例,假如Repositories
里面封装了5个方法,每个都使用了Model
,那么我在Controller
里调用了这5个方法,Model
就被new了5次。
目前在网上看到一种办法,就是在Repositories
的构造函数里注入Model对象,放在Repositories的私有成员变量里,这样5个方法都调用当前类的私有变量就可以了。但使用起来就麻烦了,在Controller里写代码的时候,需要这样写:
$xxxBiz = new XXXBiz(\xxx\xxx\Repositories);
在Repositories里需要这样写:
$xxxRepositories = new XXXRepositories(\xxx\xx\xxxModel);
在new一个Biz
的时候,还必须传入Repositories
对象,而且命名空间还老长,我基本都是在拼字符串了,写代码效率超低,还要打开这写文件,去把名字拼出来。
想问一下大家在用Laravel开发项目的时候,是如何解决Model这种逻辑层类复用的情况?
0x0 前言
有趣的问题,Yii 在业界也是被公认为性能比 Laravel 高的一个框架。于是我想单从 ActiveRecord 的构造,看看两大框架的具体实现。
0x1 Laravel 的 Eloquent 框架
在 Laravel 中可以很轻松地使用关系查询:
我在 User 类里并没有找到 find 方法,WTF,发生了什么!?
User 的基类是 Model,使用静态调用,所以会调用 Model 的 __callStatic 魔术方法:
其实就是再调用 __call 魔术方法:
追根溯源,我们发现其实 find 方法来自 IlluminateDatabaseEloquentBuilder,而该类内部使用 IlluminateDatabaseQueryBuilder 的实现。
等等,IlluminateDatabaseEloquentBuilder 和 IlluminateDatabaseQueryBuilder 的区别是啥?
其实 EloquentBuilder 是对 QueryBuilder 的进一步封装,以便更好的实现关系对象查询。
那么,其实过程为:
也就是说,你每次 静态调用 Model 的方法,都会实例化一次 Model,走一次过程。
0x2 Yii 1.1 中的 CActiveRecord
题主既然用到 model 方法,那应该是 1.1 的版本,模块继承自 CActiveRecord(Yii2 中则继承自 YiidbActiveRecord)。
好了,伙计们,现在使用 Yii 实现关系查询,先定义:
查询:
明显查询对象来自 model,看看父类怎么实现这个函数:
findAllByPk 方法直接封装于 CActiveRecord 内部:
所以其过程为:
0x3 使用 Laravel 的依赖注入
通常情况下(无参数的构造函数或注入参数已配置),Laravel 会自动帮你实例化:
所以你可以很轻松复用同一个对象:
实现完仓库后,你需要手动实例化吗:
不,这不符合 Laravel 的哲♂学,你可以如此简单:
是的,没错,你无需手动构造,传入 User 实例等等,一切只是一个简单的自动注入。而且题主注意到这里使用了命名空间,所以你只需 use 一次。(当然如果你不想拼写这么长的命名空间,那你是时候换一款 IDE 了,PhpStorm 中可以使用 Alt + Enter 快速导入
0x4 最后
对于静态和非静态开销的问题,在 StackOverflow 上有一篇讨论:http://stackoverflow.com/questions/14727...
所以说到底还是看业务需求嘛23333
通过依赖注入呀
直接可以注入到Controller中
可以看看这个文章
http://slides.com/howtomakeaturn/model#/
我假定你对Laravel还不是很了解。
第一,Laravel的Model也就是模型,不需要显式的实例化,调用方式像下面这样(摘自官方文档):
第二,你的描述有错误。你寻找的不是工厂模式(factory pattern),而是单例模式(singleton pattern),对象在一次请求生命周期之内,最多只需要实例化一次。在Laravel当中,需要用到IOC(inversion of control)容器或者说是服务容器(service container)。像下面这样:
以上只是简单的摘录,具体用法,请参考Laravel官方优秀的文档,链接如下:
Service Container(IOC容器/服务容器)
我司是继承一个BaseRepository,BaseRepository中定义
CouponRepository中
Biz中类似,继承一个BaseBiz,然后方法这么写
Controller中调用
Controller ---> Biz ---> Repository
我是这么做的,在底层 model 里建立这个函数
修改bootstrap/app.php 和 AppServiceProvider.php
具体参考 Service Provider
在controller 里调用 Foo::load() 就可以了