- 将客户端和服务器端建立一对一的联系,每个客户端都有一个唯一标识,这样服务器才能识别出来。建议唯一标识的方法有两种:使用
cookie或者通过GET方式指定。默认配置的PHP使用session的时会建立一个名叫PHPSESSID的cookie(可以通过php.ini修改session.name值指定),如果客户端禁用cookie,你也可以指定通过GET方式把session id传到服务器(修改php.ini中session.use_trans_sid等参数)。 - 客户端将
session id传递到服务器,服务器根据session id找到对应的文件,读取的时候对文件内容进行反序列化就得到session数据,保存的时候先序列化再写入文件。
PHP中类的实例化过程中,系统所做的工作大致是这样的:
PHP 5.1.0 以后 spl_autoload_register — 注册给定的函数作为 __autoload 的实现
函数原型
如果需要多条 autoload 函数,spl_autoload_register() 满足了此类需求。 它实际上创建了 autoload 函数的队列,按定义时的顺序逐个执行。相比之下, __autoload() 只可以定义一次。
当调用未定义类时,系统就会按顺序调用注册到 spl_autoload_register() 函数的所有函数
现在,我们来创建一个 Linux 类,它使用 os 作为它的命名空间(建议文件名与类名保持一致):
接着,在同一个目录下新建一个 PHP 文件,使用
这里我们使用了一个数组去保存类名与文件路径的关系,这样当类名传入时,自动加载器就知道该引入哪个文件去加载这个类了。
PSR-4 规范中必须要有一个顶级命名空间,它的意义在于表示某一个特殊的目录(文件基目录)。子命名空间代表的是类文件相对于文件基目录的这一段路径(相对路径),类名则与文件名保持一致(注意大小写的区别)。
举个例子:在全限定类名 \app\view\news\Index 中,如果 app 代表 C:\Baidu,那么这个类的路径则是 C:\Baidu\view\news\Index.php
我们就以解析 \app\view\news\Index 为例,编写一个简单的 Demo:
通过这个 Demo 可以看出限定类名转换为路径的过程。那么现在就让我们用规范的面向对象方式去实现自动加载器吧。
首先我们创建一个文件 Index.php,它处于 \app\mvc\view\home 目录中:
接着我们在创建一个加载类(不需要命名空间),它处于 \ 目录中:
最后,将 Loader 类中的 autoload 注册到 spl_autoload_register 函数中:
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。
Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。
|
|
优先级
从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。
Example #2 优先顺序示例
如何排查PHP程序性能瓶颈
- 性能优化的核心问题
哪里有性能问题。 - 最佳线程数
很多资料上有讲N + 1,或者N - 1,这两种情况在保证线程持续运行的情况,也许可以适用;但是在时间的应用场景中,一个业务的处理,线程不可能一直处理运行状态,比如当调用外部WS,或者DB操作时,都有可能存在IO阻塞,在这段时间线程是没有运行的,因此如果只是按照核数确定线程数,不太合理。 - 请求响应时间(线程执行总时间
一个请求开始到结束的总时间,也就是一个线程执行的总时间,包括线程在CPU上运行的时间+线程阻塞等待的时间。 - 资源占用时间
首先要搞明白,何为资源?很多人第一个想到的肯定是CPU,性能优化的核心问题是:哪里有性能问题?那些资源有性能问题。并发情况下,资源的抢占是影响性能的主要原因。在某些业务场景,CPU是主要的瓶颈资源,业务执行,占用了大量的CPU运算时间,并发请求主要在等待CPU的调度执行,因此,此时,CPU为瓶颈资源,资源占用时间=业务在CPU上运行的时间。还有的场景,在等待稀有的共享资源,比如数据库连接,或者数据库锁。比如锁为昂贵的稀缺资源,锁具有互斥排他性,一个线程占据锁,其他线程必须阻塞等待,此时并发性能受到严重的影响。因此,此时,锁为瓶颈资源,资源占用时间=业务在锁独占时间。 还有的场景,调用外围时,外围的响应时间较长,这种情况也造成QPS较低,外围响应时间较长,如果没有很好的超时机制,会带来比较严重的后果。单纯的增加线程池数量,或者等待队列的长度,可以提高应用的吞吐量,但是可能有很大的负载压力。 资源并行数
同一个时间点,可以并发执行的请求数。比如CPU场景下,并行数=CPU核数;锁独占的情况下,如果共享资源一个,那么并行数=1。最佳线程数 = 线程执行总时间 / 资源占用时间 * 资源并行数
缓存穿透问题
- 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
- 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
缓存穿透:查询一个必然不存在的数据。比如文章表,查询一个不存在的id,每次都会访问DB,如果有人恶意破坏,很可能直接对DB造成影响。解决办法:对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。