laravel php扩展,Laravel深入学习7 - 框架的扩展-程序员宅基地

技术标签: laravel php扩展  

声明:本文并非博主原创,而是来自对《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,当然也不是原汁原味的翻译,能保证90%的原汁性,另外因为是理解翻译,肯定会有错误的地方,欢迎指正。

欢迎转载,转载请注明出处,谢谢!

框架的扩展

介绍

Laravel为我们提供了很多自定义系统组件的扩展点,你甚至可以完全的替换掉他们。比如,哈希结构是由HasherInterface接口约定的,你可以根据你的应用来实现自己的需求。你也可以扩展自己的Request对象,并添加自己的“辅助”方法。甚至我们完全添加自己的认证、缓存、SESSION驱动。

Laravel组件扩展通常有两种方法:向IoC容器中绑定自己的接口实现;痛过使用“工厂模式”实现的Manager类注册自己的扩展。本章将探索多种扩展框架的方法,以及必要的测试代码。

扩展方式

牢记Laravel组件扩展的两种方式:IoC容器绑定和使用Manager类注册。类库管理类以工厂模式实现,负责诸如缓存、session等驱动的实例化。

类库管理类和工厂方法

Laravel有诸多Manager类库来管理创建那些基于驱动的组件。它包括缓存、session、认证、队列组件。管理类的职责是根据应用的配置来创建特殊的驱动实例。例如,CacheManager可以创建APC、Memcached、Native、以及其他缓存驱动系统的实现。

所有这些管理器都有个extend方法,可以轻易的将新的驱动功能注入到其中。对于上面所有的管理器,我们通过实例来演示如何注入我们自定义的那些服务驱动。

学习我们自己的管理器

请花一些事件来熟悉下Laravel提供的Manager类库,如CacheManager、SessionManager。通读这些代码可以让你加深理解。所有的管理器类都继承自IlluminateSupportManager基类,他为每个具体的管理器提供了很多常见使用的方法。

缓存 Cache

我们通过在CacheManager类中的extend方法绑定自定义的驱动解析器来扩展Laravel的缓存机制。比如,注册一个“mongo”驱动到缓存驱动中,代码如下:

Cache::extend('mongo', function($app)

{

// Return IlluminateCacheRepository instance...

});

传入method方法的第一个参数是驱动名称。通常和app/config/app.php配置文件中的driver选项匹配。第二个参数是返回IlluminateCacheRepository实例的闭包。闭包须要传入继承自IlluminateFoundationApplication和IoC容器的实例化对象$app。

对于我们自定义的缓存驱动,要实现IlluminateCacheStoreInterface接口的约定。因此,我们的MongoDB缓存实现代码为这样:

class MongoStore implements IlluminateCacheStoreInterface {

public function get($key) {}

public function put($key, $value, $minutes) {}

public function increment($key, $value = 1) {}

public function decrement($key, $value = 1) {}

public function forever($key, $value) {}

public function forget($key) {}

public function flush() {}

}

我们只需要使用MongoDB连接来实现上述类中的各个方法即可。当完成上述实现,就可完成我们自定义的驱动注册:

use IlluminateCacheRepository;

Cache::extend('mongo', function($app)

{

return new Repository(new MongoStore);

}

如上可见,我们可使用IlluminateCacheRepository来直接创建我们自定义的缓存驱动,而无需创建自己的(Repository)仓库类。

如果不知道该把代码放在哪里,可以考虑放到Packagist!或者在应用主目录下创建一个Extensions命名空间的目录存放。例如你的应用起名叫个Snappy,可以把这个扩展放到app/Snappy/Extensions/MongoStore.php。Laravel创建的应用没有死板的各种结构的要求,根据你的喜好自己来组织就好。

何处引入扩展

如果你还在考虑该在何处引入扩展,不妨继续使用服务提供器。我们已经讨论过这是组织我们代码的一个利器,要善用利器。

Session 会话

扩展Session机制其实像扩展缓存机制一样简单。同样,使用extend方法来注册我们自己的驱动:

Session::extend('mongo', function($app)

{

// Return implementation of SessionHandlerInterface

});

注意,我们自定义的驱动须要实现SessionHandlerInterface接口。此接口是被包含在PHP5.4+核心中的。如果你在使用PHP5.3,Laravel也是向前兼容的,Laravel已经为您定义好此接口。接口中包含了一些我们须要实现的方法。一个基于MongoDB实现的驱动代码如下:

class MongoHandler implements SessionHandlerInterface {

public function open($savePath, $sessionName) {}

public function close() {}

public function read($sessionId) {}

public function write($sessionId, $data) {}

public function destroy($sessionId) {}

public function gc($lifetime) {}

}

这些方法不像StoreInterface接口那样秒懂,让我们来快速过一遍这些方法:

open方法一般是在基于文件系统的实现中被用到。自从Laravel基于以PHP自身的本地存储实现了native会话驱动方式,你基本上不需要在本方法中添加任何东西了。你可以把他留空。PHP这种接口设计很显然是一种不好的设计方式(我们后续讨论)。

close方法同open方法,通常不用理会。大多数驱动都不需要他。

read方法返回根据$sessionId变量关联session数据的字符串。这里不需要进行序列化或者其他类型的转义,Laravel已经帮你进行了处理。

write方法根据$sessionId关联session数据将$data数据写入持久化存储系统中,如MongoDB、Dynamo等。

gc方法将根据$lifetime指定UNIX时间戳销毁之前所有的session数据。对于可以自动删除过期数据的系统比如Memcached或者Redis,该方法留空即可。

当实现SessionHandlerInterface之后,我们就可以向Session管理器中注册他了:

Session::extend('mongo', function($app)

{

return new MongoHandler;

});

当会话驱动注册之后,在配置文件app/config/session.php中指定mongo配置就能使用我们自定义的session驱动了。

分享你的成果

记住,如果你实现了自己的session驱动,可以在Packagist上分享给大家!

认证

类似缓存和会话扩展,我们继续从method方法开始:

Session::extend('mongo', function($app)

{

return new MongoHandler;

});

接口UserProviderInterface的实现指责是从各种持久化存储系统如MySQL、Riak等中获取数据,并返回接口UserInterface实现的对象。这两个接口可以让Laravel专注于验证本身,而无需关心用户数据的存储实现,以及用户对象是那种类来表示的问题。

让我们先看一下UserProviderInterface接口:

interface UserProviderInterface {

public function retrieveById($identifier);

public function retrieveByCredentials(array $credentials);

public function validateCredentials(UserInterface $user, array $credentials);

}

retrieveById方法通常接收的参数是一个唯一标识符,例如MySQL数据库中的主键自增索引ID。该方法将获取$identifier对应的数据,并返回接口UserInterface实现类的实例化对象。

当用户试图登录系统时,retrieveByCredentials方法接收参数是一个验证数组,同时他也是传入Auth::attempt的参数。该方法会“查询”给定的用户验证数据,通常,它会根据$credentials['username']运行一个“查询”条件语句来匹配数据。请不要用本方法进行任何密码的校验或验证。

方法validateCredentials会通过对比$user和$credentials来验证用户。例如,方法中会对$user->getAuthPassword();得到的字符串和$credentials['password']通过Hash::make加密后的结果进行对比。

上面我们探索了UserProviderInterface中的各个方法,接下来看一看UserInterface接口。记住,上面提供器中的retrieveById和retrieveByCredentials方法返回的就是本接口实现类的实例化对象:

interface UserInterface {

public function getAuthIdentifier();

public function getAuthPassword();

}

接口很简单。getAuthIdentifier返回用户的“主键索引”。在MySQL后台存储系统中,这里就指代用户表的主键自增索引。getAuthPassword返回用户密码的哈希值。这种接口的实现方式使认证系统和User类完全分离,并能在各种类型的实现下正常工作,而不用关心我们用的是ORM方式还是其他存储层实现的方式。在app/models下,Laravel已经实现了该接口的User类,你可以参考下这个类。

实现接口UserProviderInterface后,我们就做好了将我们的扩展注册进Auth门面的准备:

Auth::extend('riak', function($app)

{

return new RiakUserProvider($app['riak.connection']);

});

在method注册之后,我们就能在app/config/auth.php中切换新的验证驱动了。

基于IoC容器的扩展

几乎所有Laravel框架包含的服务提供器都是作为对象绑定到IoC容器中的。在配置文件app/config/app.php中有详细的列表。有时间的话,最好过一遍源码。这样,你能了解框架都加载了哪些服务,也就是容器中绑定的各式的服务。

比如,PaginationServiceProvider把paginator绑定到容器中,他对应的是IlluminatePaginationEnvironment的实例。你可以很容易的通过扩展重写这些类并重新绑定到容器中。又如,我们来扩展下基础的Environment类:

namespace SnappyExtensionsPagination;

class Environment extends IlluminatePaginationEnvironment {

//

}

扩展完成之后,在创建一个新的SnappyPaginationProvider服务提供器,并在boot方法中替换掉原有的paginator:

class SnappyPaginationProvider extends PaginationServiceProvider {

public function boot()

{

App::bind('paginator', function()

{

return new SnappyExtensionsPaginationEnvironment;

}

parent::boot();

}

}

注意,本类继承的PaginationServiceProvider,并不是默认的ServiceProvider。当完成扩展之后要记住app/config/app.php中替换成自己的扩展名称。

这就是对容器中已经绑定的核心类库进行扩展的方法。实际上,所有核心类库都能用这种方式进行重写。深入阅读源码,能帮你熟练知晓Laravel是怎么将各个部分组织在一起运转的。

请求的扩展

因为在每个请求的生命周期中,请求是很早就会被实例化的一个最基础的部分,所以Request的扩展会有稍许不同。

首先,还是像往常一样实现一个子类:

namespace QuickBillExtensions;

class Request extends IlluminateHttpRequest {

// Custom, helpful methods here...

}

然后,打开bootstrap/start.php,它是请求到达应用时最早被包含的文件。注意这里被执行的第一个动作就是创建Laravel的实例化对象$app:

$app = new IlluminateFoundationApplication;

当对象被创建,同时也会创建IlluminateHttpRequest实例,并以request键绑定到IoC容器中。这里,我们应该另辟途径实现一个类来作为“默认的”请求类型,对不对?还好,requestClass方法就能帮我们那实现它!所以我们需要在bootstrap/start.php文件开头加上这样一行:

use IlluminateFoundationApplication;

Application::requestClass('QuickBillExtensionsRequest');

当添加玩自定义的请求类后,Laravel在任何地方都能用到我们的这个自定义的Request实例,这能使我们实现的定义请求类的实例可用,甚至在单元测试中也能使用。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33344629/article/details/115538365

智能推荐

5个超厉害的资源搜索网站,每一款都可以让你的资源满满!_最全资源搜索引擎-程序员宅基地

文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎

Book类的设计(Java)_6-1 book类的设计java-程序员宅基地

文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java

基于微信小程序的校园导航小程序设计与实现_校园导航微信小程序系统的设计与实现-程序员宅基地

文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。

有状态和无状态登录

传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。

九大角度全方位对比Android、iOS开发_ios 开发角度-程序员宅基地

文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度

搜索引擎的发展历史

搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。

随便推点

控制对象的特性_控制对象特性-程序员宅基地

文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性

FRP搭建内网穿透(亲测有效)_locyanfrp-程序员宅基地

文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp

UVA 12534 - Binary Matrix 2 (网络流‘最小费用最大流’ZKW)_uva12534-程序员宅基地

文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534

免费SSL证书_csdn alphassl免费申请-程序员宅基地

文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请

测试算法的性能(以选择排序为例)_算法性能测试-程序员宅基地

文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试

Lane Detection_lanedetectionlite-程序员宅基地

文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite

推荐文章

热门文章

相关标签