所以这个 register 到底是用来干嘛的?

例子里的$this->app->singleton又是干嘛用的?
有任何(Laravel的)新手看到这个文档能理解这部分的内容,我从此就转行不干了。
不喷翻译,纯粹是喷写文档的程序员水平太低(不是指“写代码”的水平)。

本帖已被设为精华帖!
本帖由系统于 2年前 自动加精
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
liuqing_hu
最佳答案

@leo @DianWang @kiyoma

先回答问题

  • ServiceProvider 中的 register 到底是做什么用的

简短一点:就是文档中提到的用于「注册服务」。

详细一点:

  1. 什么是服务:就是我们在项目中需要使用到的功能(组件或者说模块)
  2. 服务如何注册:这里解释 $this->app->singleton 用途, 通过服务容器($this->app)的 singleton 方法($this->app->singleton('your_service', closure)) 将服务(your_service) 绑定到容器,后续可以通过 $this->app->make('your_service') 解析出具体服务实例。
  3. register 里面能干什么:在 register 里仅能够完成绑定(包括 bind, singleton)操作;为什么仅能支持绑定操作呢?因为项目错综复杂,一个服务(功能或模块)可能依赖于其它服务,如果在 register 方法内执行其它操作(这里具体指解析服务( make(your_service))),那么可能在 服务容器执行依赖注入解析(实例化服务)时所依赖的服务可能还没有完成注册即绑定操作(这时就无法解析出( make) 这个依赖服务实例)从而导致出错。

再来撕 x(避免误伤这里指官方文档)

Laravel 的官方文档对初学者(不是指 PHP 初学者,指 Laravel 初学者)特别不友好,以至于光看文档基本上不会太明白他能干什么!


如果需要彻底搞明白服务提供者,我们至少需要了解

5年前 评论
funbox 4年前
tankeban123 2年前
讨论数量: 44
liuqing_hu

@leo @DianWang @kiyoma

先回答问题

  • ServiceProvider 中的 register 到底是做什么用的

简短一点:就是文档中提到的用于「注册服务」。

详细一点:

  1. 什么是服务:就是我们在项目中需要使用到的功能(组件或者说模块)
  2. 服务如何注册:这里解释 $this->app->singleton 用途, 通过服务容器($this->app)的 singleton 方法($this->app->singleton('your_service', closure)) 将服务(your_service) 绑定到容器,后续可以通过 $this->app->make('your_service') 解析出具体服务实例。
  3. register 里面能干什么:在 register 里仅能够完成绑定(包括 bind, singleton)操作;为什么仅能支持绑定操作呢?因为项目错综复杂,一个服务(功能或模块)可能依赖于其它服务,如果在 register 方法内执行其它操作(这里具体指解析服务( make(your_service))),那么可能在 服务容器执行依赖注入解析(实例化服务)时所依赖的服务可能还没有完成注册即绑定操作(这时就无法解析出( make) 这个依赖服务实例)从而导致出错。

再来撕 x(避免误伤这里指官方文档)

Laravel 的官方文档对初学者(不是指 PHP 初学者,指 Laravel 初学者)特别不友好,以至于光看文档基本上不会太明白他能干什么!


如果需要彻底搞明白服务提供者,我们至少需要了解

5年前 评论
funbox 4年前
tankeban123 2年前

初学者看核心概念,犹如管中窥豹,肯定是一头雾水。

通过整体再看细节就会明白其用意。

一、映射到现实

需求:

建设公司盖楼

角色:

  • 采购部(饰演服务提供者)
  • 库房(饰演服务容器)
  • 所需工具(饰演服务)有安全帽、手套、锤子、推车、推土机、塔吊等。
  • 商人(饰演工具提供者)
  • 工人(饰演工具消费者,也是盖楼实现者)

流程:

  1. 开始盖房前,各个商人向采购部上报自己的提供工具。(register 阶段)
  2. 采购部门将各个工具采购并放入库存。(服务提供者处理就绪阶段)
  3. 工人各自的准备阶段(boot 阶段)
  4. 工人开始建造,需要的工具到采购部领取(make 阶段)
  5. 楼房盖好。

说明

  1. register 阶段只能填报自己提供工具,不应该干其他的事情,应为干其他事情就有可能需要到工具,但现阶段采购部还没有采购到工具。所有应将其他事情放到 boot 阶段。
  2. 对应安全帽应该人手一份。对应塔吊只有一个,大家一起用,使用 singleton() 上报,对于暂时无货(延迟)也可以上报,需要是再去购买。

二、回到程序

需求:

建立学管系统

角色:

  • 服务提供者
  • 服务容器
  • 所需服务 有消息通知、缓存、数据库连接、短信下发,学管订单。
  • Redis 提供缓存 、 MySqlMongoDB提供数据库 ,EasySMS 提供短信下发
  • 系统的各个功能、模块(自己名下学生续费成功后给班主任发送短信通知)

流程:

  1. RedisMySQLEasySMS,编写服务提供者 RedisServiceProviderMySQLServiceProviderEasySMSServiceProvider 并配置到 Laravel 的 config/app.php 文件中有一个 providers 数组进行上报。(register 阶段)
  2. Laravel Application 处理服务提供者列表,并将所提供的服务放入到服务容器中。(服务提供者处理就绪阶段)
  3. EasySMSServiceProvider 需要用到缓存的功能,OK,Laravel 从服务容器中取到 RedisServiceProvider 所提供的 Redis 对象给它使用。(boot 阶段)
  4. 功能开发阶段。例:需要给教师手机号发送一条短信,OK,通过 app::make('sms') (sms 为别名) 获取 EasySMS 对象实现短信发送。(make 阶段)
  5. 系统开发完成

说明

  1. EasySMSServiceProvider 需要用到缓存的功能代码如果放到 register 阶段将会报错,应该 缓存服务提供者 可能还没注册,或者服务容器中什么服务也还没有。
  2. 短信功能大家可以共用一个对象(单例模式),所以使用 $this->app->singleton() 注册服务比较好,普通的服务(非单例)用 $this->app->bind() 注册。对了,并不是每次系统运行都会用到短信发送功能,为了提升系统速度,我们可以延迟注册,在 EasySMSServiceProvider 类中将 $defer 属性设置为 true 即可。

三、回答问题

laravel 将依次调用 服务提供者register()方法来进行服务注册,服务注册成功后再依次调用 服务提供者boot()方法。我们可以在 register() 方法中注册多个服务。

singleton() 是注册单例对象服务的方式,注册后,其他地方所用到该服务的对象都是同一个对象。

4年前 评论
funbox 4年前
maorui 3年前
Shixi 11个月前

@DianWang 谢谢回答。
不过还是没能完全解惑。
“暂时用不到的话,没必要纠结,知道能做什么就行”,我同意这句话,事实上,我就是想了解一下这玩意儿能做什么,并没打算彻底弄懂里面的原理,立马实战什么的。
但无论你的回答也好,官方文档也好,都仅仅只提到了“注册服务”、“绑定一个类”这样浮于表面的抽象说法。说实话,对新手极为不友好。为什么写出了这么好的框架的人,不能好好地把其中的设计理念、最佳实践,好好介绍出来呢?这可是官方文档啊,任何一个初学Laravel的人都会先来看这个东西。
我生气的是为这个——老鸟活在自己的世界观里,根本无法理解菜鸟看到的世界是怎么样的。编程的门槛现在很低,但同时也不低,每个入门的人都浪费了大量的时间,走了大量的弯路。

5年前 评论

@leo 你说的很对。不过这就是一个相对的问题。
如果我是一个刚看了两眼PHP就不知天高地厚来学Laravel的愣头青,然后看到这篇文档看不懂了,并且来评论区大放厥词,那显然是不对的。
但我既然已经在深究ServiceProvider了,显然不是那个级别的菜鸟了(就算是菜鸟,也是摸爬滚打过的鸟了吧)。
这个文档,将register的部分,我睁大言情看了半天——
···
在 register 方法中,你只需要将类绑定到 服务容器 中。而不需要尝试在 register 方法中注册任何事件监听器、路由或者任何其他功能。否则,你可能会意外使用到尚未加载的服务提供器提供的服务。
···
第一句话讲了什么?没讲register是干什么的,设计理念是什么,直接就说了一句类似“使用时要注意的小tip”一样的东西,你觉得新人看到这里是不是一头雾水?
接下来是一段代码示例,就是那个看不懂的singleton。
然后又是一句话:
···
这个服务提供器只定义了一个 register 方法,并使用该方法在服务容器中定义了一个 Riak\Connection 实现。 如果你不了解服务容器的工作原理,请查看其 文档.
···
我真是艹了。这文档到最后都说什么了?
我要是都懂我还需要来看这篇文档吗?

5年前 评论
DianWang

你新建个完成特殊功能的服务,比如websocket,自定义的邮件,缓存,ftp或其他一些完成特殊功能的类等等,你想要把服务引入到系统中去,就要使用这个register,$this->app->singleton('xxx', Simple::class),这样Simple就被以单例的方式注册进了系统,使用的时候可以在任何地方直接app::make('xxx')调用,而无须再用use引入了。

5年前 评论
DianWang

你新建个完成特殊功能的服务,比如websocket,自定义的邮件,缓存,ftp或其他一些完成特殊功能的类等等,你想要把服务引入到系统中去,就要使用这个register,$this->app->singleton('xxx', Simple::class),这样Simple就被以单例的方式注册进了系统,使用的时候可以在任何地方直接app::make('xxx')调用,而无须再用use引入了。

5年前 评论

@DianWang 所以singleton是用于引入单例的?那除了写singleton,register里还能干什么呢?
在register里做的事情有哪些共同特性?
在boot方法里又是做哪些事情的,和register里做的事情有哪些不同?

5年前 评论
DianWang

这是一种服务容器的设计模式,要实现什么功能,取决于你自己的需要。boot是register完成后,你想要完成的事情。
register就是用来注册服务的,它也只做这件事。论坛一堆讲原理的文章,搜一下并不难。另外暂时用不到的话,没必要纠结,知道能做什么就行。

5年前 评论

@DianWang 谢谢回答。
不过还是没能完全解惑。
“暂时用不到的话,没必要纠结,知道能做什么就行”,我同意这句话,事实上,我就是想了解一下这玩意儿能做什么,并没打算彻底弄懂里面的原理,立马实战什么的。
但无论你的回答也好,官方文档也好,都仅仅只提到了“注册服务”、“绑定一个类”这样浮于表面的抽象说法。说实话,对新手极为不友好。为什么写出了这么好的框架的人,不能好好地把其中的设计理念、最佳实践,好好介绍出来呢?这可是官方文档啊,任何一个初学Laravel的人都会先来看这个东西。
我生气的是为这个——老鸟活在自己的世界观里,根本无法理解菜鸟看到的世界是怎么样的。编程的门槛现在很低,但同时也不低,每个入门的人都浪费了大量的时间,走了大量的弯路。

5年前 评论
leo

@kiyoma

这需要你掌握容器、单例等基础概念,如果你看不懂说明你的基础知识还不足以学习和掌握这块的知识,需要你自己去补习相关的知识。

我生气的是为这个——老鸟活在自己的世界观里,根本无法理解菜鸟看到的世界是怎么样的。 如果按你这么说,那 Laravel 文档里是不是还应该教你怎么写 PHP 代码呢?毕竟菜鸟可能还没学过 PHP 呢。

5年前 评论
kevlin 2年前

@leo 你说的很对。不过这就是一个相对的问题。
如果我是一个刚看了两眼PHP就不知天高地厚来学Laravel的愣头青,然后看到这篇文档看不懂了,并且来评论区大放厥词,那显然是不对的。
但我既然已经在深究ServiceProvider了,显然不是那个级别的菜鸟了(就算是菜鸟,也是摸爬滚打过的鸟了吧)。
这个文档,将register的部分,我睁大言情看了半天——
···
在 register 方法中,你只需要将类绑定到 服务容器 中。而不需要尝试在 register 方法中注册任何事件监听器、路由或者任何其他功能。否则,你可能会意外使用到尚未加载的服务提供器提供的服务。
···
第一句话讲了什么?没讲register是干什么的,设计理念是什么,直接就说了一句类似“使用时要注意的小tip”一样的东西,你觉得新人看到这里是不是一头雾水?
接下来是一段代码示例,就是那个看不懂的singleton。
然后又是一句话:
···
这个服务提供器只定义了一个 register 方法,并使用该方法在服务容器中定义了一个 Riak\Connection 实现。 如果你不了解服务容器的工作原理,请查看其 文档.
···
我真是艹了。这文档到最后都说什么了?
我要是都懂我还需要来看这篇文档吗?

5年前 评论
leo

@kiyoma 如果你看不懂 singleton 说明你对单例一无所知,所以看不懂这篇文档是必然的。

文档不是用来教你基础概念的,而是在你已经掌握基础概念的情况下告诉你在本框架中应该怎么用。

5年前 评论
leo

当然另外一个问题就是翻译的质量比较差,反正对于一些常用软件的文档我都是看英文原版的,不会因为翻译本身的问题让我理解出错。

5年前 评论
leo

看了一下原文,这里的翻译确实是有很大的问题:

在 register 方法中,你只需要将类绑定到 服务容器 中。而不需要尝试在 register 方法中注册任何事件监听器、路由或者任何其他功能。否则,你可能会意外使用到尚未加载的服务提供器提供的服务。

原文:

As mentioned previously, within the register method, you should only bind things into the service container. You should never attempt to register any event listeners, routes, or any other piece of functionality within the register method.

这里的 should never 应该翻译成 不允许 而不是 不需要

5年前 评论
DianWang

@kiyoma 这是基础知识问题,爱莫能助了,这个问题我已经回答完毕。我们只能给你指条思路,能不能从坑里爬出来,要靠你自己。

5年前 评论
元大明 4年前
DianWang (作者) 4年前

一年前我也像你这样不懂,不同的是我怀着敬畏的心去理解和学习的,首先你态度不对,你是学习人家的东西(还是免费),自己多看源码,多去思考不要抱怨,我也是花好长时间才理解的这部分内容!慢慢学习

5年前 评论

@helloBear 你认为你的智商合格吗(不是在侮辱你)?
如果合格的话,那么想想,以你现在“已经懂了”的眼光看看你一年前“什么都不懂”的那些东西,你觉得它们真的很难吗?
你觉得它们就应该让你用那么长时间读源码,才理解吗?
这难道不是一种没必要走的弯路吗?
学习也是分高效和低效的。
一句话,这文档写的就是烂。敬畏之心不是用在这个地方的,我敬畏大神框架设计的优雅,里面很多理念都是我没见识过的。但我也很清楚,它这文档就是写的烂——程序员根本不懂怎么让人明白一件事。越是大牛越容易和新手视野不一样,越是想不到需要在文档中明确哪些东西。

5年前 评论
meows 4年前
meows 4年前
being1994 4年前
liuqing_hu

@leo @DianWang @kiyoma

先回答问题

  • ServiceProvider 中的 register 到底是做什么用的

简短一点:就是文档中提到的用于「注册服务」。

详细一点:

  1. 什么是服务:就是我们在项目中需要使用到的功能(组件或者说模块)
  2. 服务如何注册:这里解释 $this->app->singleton 用途, 通过服务容器($this->app)的 singleton 方法($this->app->singleton('your_service', closure)) 将服务(your_service) 绑定到容器,后续可以通过 $this->app->make('your_service') 解析出具体服务实例。
  3. register 里面能干什么:在 register 里仅能够完成绑定(包括 bind, singleton)操作;为什么仅能支持绑定操作呢?因为项目错综复杂,一个服务(功能或模块)可能依赖于其它服务,如果在 register 方法内执行其它操作(这里具体指解析服务( make(your_service))),那么可能在 服务容器执行依赖注入解析(实例化服务)时所依赖的服务可能还没有完成注册即绑定操作(这时就无法解析出( make) 这个依赖服务实例)从而导致出错。

再来撕 x(避免误伤这里指官方文档)

Laravel 的官方文档对初学者(不是指 PHP 初学者,指 Laravel 初学者)特别不友好,以至于光看文档基本上不会太明白他能干什么!


如果需要彻底搞明白服务提供者,我们至少需要了解

5年前 评论
funbox 4年前
tankeban123 2年前
DianWang

@liuqing_hu :joy:我从头到尾理性答题一句没撕啊,大佬可以close这个issue了

5年前 评论

@DianWang 大家都很理性,其实这也不算撕逼,就是我单方面在发牢骚,因为我被这文档搞得很生气(大家好像认为文档写成这是理所当然的,这导致我怨气更重了)

5年前 评论

@liuqing_hu 真心感谢大佬,不光解决了我的疑问,还顺便帮我去火了。
文档里如果写了$this->app->singleton再提下$this->app->make,至少还能给人一个脑补的方向,查资料的关键词。
不说了。。。。
底下的两篇文章链接我会好好看看的。

5年前 评论
ibucoin

在这个上一章的服务容器中就有讲到单例绑定和make方法了,这个真心不能喷。
另外你可以看看tp5的文档,有些特性我得去看别人评论才知道能这么用,这不更糟心。

5年前 评论
pardon110

其实做技术,是需要一定公设的。比如知识链A->B->C->D,由低级到高级。如果你知道A了解B,与你讲B哪怕是C,你可能会明白一点点,但若一开始与你讲D的知识,你会觉得这是什么鬼?看起来貌似都懂,做起来一脸??。对于这种情况,你至少有两种思路去解决,一 不管原理,先实现,有时间再深究。二,笨方法,也是最快的方法,读源码(好的代码会说话),D不懂没关系 ,你可以找到路径C,依次类推,直到找到能让你懂的点,串起来形成自己的知识体系。在这探索期间,不要觉得难,难的原因是你不会,不会学就好了。唯一可虑的是,总想一气呵成,而忘记了事实是检验真理唯一标准。至于laravel,真心话并非是适合菜鸟的入门框架。承认现实,每日精进。总有一天菜鸟会变老鸟。

5年前 评论

可以看看我写的Laravel核心的实现原理,没准会清楚不少。 https://github.com/kevinyan815/Learning_La...

5年前 评论

Laravel 源代码看起来最艺术的就是运用了大量的设计模式,代码看起来最难的也是运用了大量的设计模式。官方文档难懂的地方在于对其中的设计模式没有说明,只写了基本的用法。所以其实官方文档只是告诉怎么入门 Laravel,怎么拿来做一个简单的功能,没有告诉你这里为什么要这么做。为什么要这么做呢,见仁见智吧。觉得Laravel设计臃肿的人也不在少数。

5年前 评论

实际上就是设计模式中的一种,依赖注入,regisister就是负责注入用的

5年前 评论

这东西就是让使用包的人爽的根本。他帮助你把设置都搞好。把痛点都处理好。(前提是你经历过,没有就不能理解。)
要是那天真用到,基本也要看包的源码对着来用。
不是文档能说明白的。

5年前 评论

@kiyoma 说实话,这个文档确实对新手不友好,作为新手的我也是看着一脸懵逼,我建议你去看一本书《Laravel框架技术解析》--陈昊 ,然后耐心的去跟着节奏去分析源码,也许你就明白了。(我目前正在看这本书,虽然是基于5.1的,但是核心内容没有变)

5年前 评论
小花儿

@AmberLavigne 会不会有点旧啊,现在都5.7了

5年前 评论

@yangwb1 如果你的切入点是想学习框架核心,我的回答是不会

5年前 评论

@kiyoma 个人建议:可以去多读读基于 Laravel 的扩展的原码,并自己试着写一个扩展出来,相信我,写完之后你会受益良多。

5年前 评论

说来说去,就是楼主实战经验不足,所有很多东西看了不容易理解。

5年前 评论

初学者看核心概念,犹如管中窥豹,肯定是一头雾水。

通过整体再看细节就会明白其用意。

一、映射到现实

需求:

建设公司盖楼

角色:

  • 采购部(饰演服务提供者)
  • 库房(饰演服务容器)
  • 所需工具(饰演服务)有安全帽、手套、锤子、推车、推土机、塔吊等。
  • 商人(饰演工具提供者)
  • 工人(饰演工具消费者,也是盖楼实现者)

流程:

  1. 开始盖房前,各个商人向采购部上报自己的提供工具。(register 阶段)
  2. 采购部门将各个工具采购并放入库存。(服务提供者处理就绪阶段)
  3. 工人各自的准备阶段(boot 阶段)
  4. 工人开始建造,需要的工具到采购部领取(make 阶段)
  5. 楼房盖好。

说明

  1. register 阶段只能填报自己提供工具,不应该干其他的事情,应为干其他事情就有可能需要到工具,但现阶段采购部还没有采购到工具。所有应将其他事情放到 boot 阶段。
  2. 对应安全帽应该人手一份。对应塔吊只有一个,大家一起用,使用 singleton() 上报,对于暂时无货(延迟)也可以上报,需要是再去购买。

二、回到程序

需求:

建立学管系统

角色:

  • 服务提供者
  • 服务容器
  • 所需服务 有消息通知、缓存、数据库连接、短信下发,学管订单。
  • Redis 提供缓存 、 MySqlMongoDB提供数据库 ,EasySMS 提供短信下发
  • 系统的各个功能、模块(自己名下学生续费成功后给班主任发送短信通知)

流程:

  1. RedisMySQLEasySMS,编写服务提供者 RedisServiceProviderMySQLServiceProviderEasySMSServiceProvider 并配置到 Laravel 的 config/app.php 文件中有一个 providers 数组进行上报。(register 阶段)
  2. Laravel Application 处理服务提供者列表,并将所提供的服务放入到服务容器中。(服务提供者处理就绪阶段)
  3. EasySMSServiceProvider 需要用到缓存的功能,OK,Laravel 从服务容器中取到 RedisServiceProvider 所提供的 Redis 对象给它使用。(boot 阶段)
  4. 功能开发阶段。例:需要给教师手机号发送一条短信,OK,通过 app::make('sms') (sms 为别名) 获取 EasySMS 对象实现短信发送。(make 阶段)
  5. 系统开发完成

说明

  1. EasySMSServiceProvider 需要用到缓存的功能代码如果放到 register 阶段将会报错,应该 缓存服务提供者 可能还没注册,或者服务容器中什么服务也还没有。
  2. 短信功能大家可以共用一个对象(单例模式),所以使用 $this->app->singleton() 注册服务比较好,普通的服务(非单例)用 $this->app->bind() 注册。对了,并不是每次系统运行都会用到短信发送功能,为了提升系统速度,我们可以延迟注册,在 EasySMSServiceProvider 类中将 $defer 属性设置为 true 即可。

三、回答问题

laravel 将依次调用 服务提供者register()方法来进行服务注册,服务注册成功后再依次调用 服务提供者boot()方法。我们可以在 register() 方法中注册多个服务。

singleton() 是注册单例对象服务的方式,注册后,其他地方所用到该服务的对象都是同一个对象。

4年前 评论
funbox 4年前
maorui 3年前
Shixi 11个月前

从头到尾没觉得这个框架如何如何厉害了,只是组件多用着方便而已。你能想象随便一个实例的内容,要用1G的内存去写文件吗,就算你只是输出一个hello worl,可以想象一下,这个框架一次加载了多少文件。如果你不用XDEBUG,可以这么说,你很难排查中间组件的错误,因为全是依赖注入,非常多的地方还是自动注入,这就给排查带来了更大的麻烦,虽然能解决,但是耗费的时间可不少。

4年前 评论
命中水

同样是看到服务容器/服务提供者一头雾水的,我赞同题主的观点,文档翻译的很烂,一些很重要的点完全没有说清。官方文档做到这种程度,只能找一些博主写的文章来结合了。

4年前 评论
kiyoma (楼主) 4年前

其实boot()的用法更加多 文档只是一笔掠过

4年前 评论

服务容器 => 房子,服务提供者 => 各种家电。 register:房子需要一个冰箱冷藏食物。 boot:房子购入了一台冰箱并开始冷藏食物。 以上个人理解。

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!