- 表单提交中的Get和Post的异同点
- echo(),print(),print_r()的区别
- 构造函数和析构函数
- 数组[‘a’, ‘b’, ‘c’] 转换成字符串 ‘abc’
- 获取字符串’aAbB’中A首次出现的位置
- 编写一段用最小代价实现将字符串完全反序, e.g. 将 “1234567890” 转换成 “0987654321”.
- 数组处理函数
- 字符串处理函数
- public、protected、private、final 区别
- 类的静态调用和实例化调用
- PHP 不实例化调用方法
- 面向对象
- 请用递归实现一个阶乘求值算法 F(n): n=5;F(# n)=5!=54321=120
- 将字符长fang-zhi-gang 转化为驼峰法的形式
- 数组内置的排序方法有哪些?
- 用PHP写出显示客户端IP与服务器IP的代码
- 语句include和require的区别是什么?为避免多次包含同一文件,可用(?)语句代替它们?
- PHP 不使用第三个变量实现交换两个变量的值
- 写一个方法获取文件的扩展名
- 用PHP打印出前一天的时间格式是2017-3-22 22:21:21
- PHP 如何接口调用?
- 用PHP header()函数实现页面404错误提示功能
- 全局变量
- 魔术方法
- 魔术常量
- 附录1:运算符优先级
- 附录2:HTTP状态码
- composer是什么?Composer和PHP有什么关系?
- composer团队协作怎么保证版本统一?
- OOP思想,特征和其意义
- OOP的七大设计原则是什么?
- mvc框架的生命周期说一下
- session与cookie的区别是什么?
- 为什么session的安全性大于cookie?
- session与cookie的应用场景有哪些?
- php7新特性
- php8新特性
- 手写一个单例模式吧
- php垃圾回收机制
- php-fpm是什么?
- php-fpm的运行模型?
- cgi,php-cgi,php-fpm,fastcgi的区别?
- php-fpm如何完成平滑重启?
- php-fpm和nginx的通信机制是怎么样的?
- 怎么选定用tcp还是套接字的方式和nginx通信?
- php-fpm在请求链路的体现,画出来?
- php-fpm有几种工作模式?
- 怎么选定php-fpm的worker进程数?
- php-fpm如何优化?
- 说下你最常用的php框架(laravel框架)的生命周期?
- 怎么理解 依赖注入(DI)与控制反转(Ioc)?
- php的弱类型是怎么实现的?
- 简单说下对php 底层变量(zval)数据结构的理解
- 常见的设计模式有哪些?
表单提交中的Get和Post的异同点
- get 请求一般用于向服务端获取数据,post 一般向服务端提交数据
- get 传输的参数在 url 中,传递参数大小有限制,post 没有大小限制,
- get 不安全,post 安全性比get高
- get请求在服务端用Request.queryString 接受 ,post 请求在服务端用Requset.form 接受
echo(),print(),print_r()的区别
-
echo: 输出一个或多个参数
-
print: 输出一个参数
-
print_r: 打印简单信息
-
var_dump: 打印带类型的变量(类型,长度,值)
构造函数和析构函数
-
构造函数:
__construct
:会在每次创建新对象时先调用此方法 -
析构函数:
__destruct
:会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行
析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余关闭操作的运行。
析构函数在脚本关闭时调用,此时所有的 HTTP 头信息已经发出。脚本关闭时的工作目录有可能和在 SAPI(如 apache)中时不同。
试图在析构函数(在脚本终止时被调用)中抛出一个异常会导致致命错误。
数组[‘a’, ‘b’, ‘c’] 转换成字符串 ‘abc’
echo implode(‘’,[‘a’, ‘b’, ‘c’]);
echo join([‘a’, ‘b’, ‘c’],'');
获取字符串’aAbB’中A首次出现的位置
$str=‘aAbB’;
echo strpos($str,"A");
编写一段用最小代价实现将字符串完全反序, e.g. 将 “1234567890” 转换成 “0987654321”.
1、使用函数
echo strrev("Hello World!");
2、不使用函数
$s = '1234567890';
$o = '';
$i = 0;
while(isset($s[$i]) && $s[$i] != null) {
$o = $s[$i++].$o;
}
echo $o;
数组处理函数
字符串处理函数
public、protected、private、final 区别
PHP 5 新增了一个 final
关键字。如果父类中的方法被声明为 final
,则子类无法覆盖该方法。如果一个类被声明为 final
,则不能被继承
类的静态调用和实例化调用
-
静态调用不需要实例化即可调用
-
静态方法不能调用非静态属性,因为非静态属性需要实例化后,存放在对象里
-
静态方法可以调用非静态方法,使用 self 关键字。php 里,一个方法被 self:: 后,自动转变为静态方法
-
调用类的静态函数时不会自动调用类的构造函数
PHP 不实例化调用方法
静态调用、使用 PHP 的反射
面向对象
- 封装:能降低依赖,实现松耦合
- 继承:子类自动继承父类的属性和方法,并可以重写,增加代码重用性,PHP不支持多继承
- 多态:多个子类虽然都继承父类的同一个方法,但是可以得到不同的结果,增加了代码的灵活性
请用递归实现一个阶乘求值算法 F(n): n=5;F(# n)=5!=54321=120
function F($n)
{
if ($n == 0) {
return 1;
} else {
return $n * F($n - 1);
}
}
将字符长fang-zhi-gang 转化为驼峰法的形式
// 方法一:
function Fun($str)
{
if (isset($str) && !empty($str)) {
$newStr = '';
if (strpos($str, '-') > 0) {
$strArray = explode('-', $str);
$len = count($strArray);
for ($i = 0; $i < $len; $i++) {
$newStr .= ucfirst($strArray[$i]);
}
}
return $newStr;
}
}
// 方法二:
function Fun($str)
{
$arr1 = explode('_', $str);
$str = implode(' ', $arr1);
return ucwords($str);
}
数组内置的排序方法有哪些?
sort($array); //数组升序排序
rsort($array); //数组降序排序
asort($array); //根据值,以升序对关联数组进行排序
ksort($array); //根据建,以升序对关联数组进行排序
arsort($array); //根据值,以降序对关联数组进行排序
krsort($array); // 根据键,以降序对关联数组进行排序
用PHP写出显示客户端IP与服务器IP的代码
$_SERVER["REMOTE_ADDR"]
语句include和require的区别是什么?为避免多次包含同一文件,可用(?)语句代替它们?
1、加载失败的处理方式不同
include与require除了在处理引入文件的方式不同外,最大的区别就是:
include在引入不存在的文件时,产生一个警告且脚本还会继续执行,
require则会导致一个致命性错误且脚本停止执行。
如果hello.php不存在,echo ‘world’这句是可以继续执行的。
如果hello.php不存在,echo ‘hello’这句是不会执行的,到require时就停止了。
2、include()是有条件包含函数,而 require()则是无条件包含函数。
3、文件引用方式
include有返回值,而require没有
可以用include_once,require_once代替,表示文件只引入一次,引入之后则不在引入,作为优化点
PHP 不使用第三个变量实现交换两个变量的值
list($b,$a)=array($a,$b);
var_dump($a,$b);
写一个方法获取文件的扩展名
//方法一
function get_extension($file){
return substr(strrchr($file,'.'), 1);
}
//方法二
function get_extension($file){
return end(explode('.', $file));
}
echo get_extension('fangzhigang.png'); //png
用PHP打印出前一天的时间格式是2017-3-22 22:21:21
$a = date("Y-m-d H:i:s", strtotime("-1 days"));
PHP 如何接口调用?
CURL
用PHP header()函数实现页面404错误提示功能
Header("HTTP/1.1 404 Not Found");
全局变量
变量名 | 说明 |
---|---|
$GLOBALS | 引用全局作用域中可用的全部变量 |
$_SERVER | 服务器和执行环境信息 |
$_GET | HTTP GET 变量 |
$_POST | HTTP POST 变量 |
$_FILES | HTTP 文件上传变量 |
$_REQUEST | HTTP Request 变量 |
$_SESSION | Session 变量 |
$_ENV | 环境变量 |
$_COOKIE | HTTP Cookies |
魔术方法
方法名 | 说明 |
---|---|
__get() | 当调用一个未定义的属性时访问此方法 |
__set() | 给一个未定义的属性赋值时调用 |
__isset() | 当在一个未定义的属性上调用isset()函数时调用此方法 |
__unset() | 当在一个未定义的属性上调用unset()函数时调用此方法 |
__call() | 当调用一个未定义(包括没有权限访问)的方法时调用此方法 |
__autoload() | 使用尚未被定义的类时自动调用 |
__construct() | 构造函数,见上 |
__destruct() | 析构函数,见上 |
__clone() | 使用clone方法复制一个对象时,对象会自动调用__clone魔术方法 |
__toString() | 将一个对象转化成字符串时自动调用 |
__sleep() | 串行化的时候用 |
__wakeup() | 反串行化的时候调用 |
__set_state() | 当调用var_export()时,这个静态 方法会被调用(自PHP 5.1.0起有效) |
__invoke() | 当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用 |
魔术常量
附录1:运算符优先级
附录2:HTTP状态码
一般记住以下几个就可以了:
- 200 :成功
- 302 :重定向
- 404 :没找到页面
- 500 :服务器内部错误
- 502 :从远程服务器接收到了一个无效的响应
- 503 :超载暂时无法处理请求
- 504 :超时,未从远端服务器获取请求
composer是什么?Composer和PHP有什么关系?
Composer 是PHP的一个依赖(dependency)管理工具,在我们的项目中声明所依赖的外部工具库(libraries),Composer 可以帮助我们安装这些依赖的库文件。Composer可以全局安装也可以局部安装,默认不是全局安装的,是基于指定项目的某个目录进行安装的。
composer团队协作怎么保证版本统一?
- 安装组件使用composer install 而不是composer update,
- .lock文件加入版本控制当中。
OOP思想,特征和其意义
-
抽象、封装、继承和多态是面向对象的基础。
-
抽象:提取现实世界中某事物的关键特性,为该事物构建模型的过程。对同一事物在不同的需求下,需要提取的特性可能不一样。得到的抽象模型中一般包含:属性(数据)和操作(行为)。这个抽象模型我们称之为类。对 类进行实例化得到对象。
-
封装:封装可以使类具有独立性和隔离性;保证类的高内聚。只暴露给类外部或者子类必须的属性和操作。类封装的实现依赖类的修饰符(public、protected和private等)
-
继承:对现有类的一种复用机制。一个类如果继承现有的类,则这个类将拥有被继承类的所有非私有特性(属性和操作)。这里指的继承包含:类的继承和接口的实现。
-
多态:多态是在继承的基础上实现的。多态的三个要素:继承、重写和父类引用指向子类对象。父类引用指向不 同的子类对象时,调用相同的方法,呈现出不同的行为;就是类多态特性。多态可以分成编译时多态和运行时多态。
-
帮助理解: https://www.cnblogs.com/waj6511988/p/6974291.html
OOP的七大设计原则是什么?
-
开闭原则:对扩展开放,对修改关闭
-
里氏替换原则:继承 必须保证 父类中的性质在子类中仍然成立
-
依赖倒置原则:面向接口编程,而不面向实现类
-
单一职责原则:控制 类的 粒度的大小 ,增强内聚性,减少耦合
-
接口隔离原则:要为各个类提供所需的专用接口
-
迪米特法则:迪米特法则(Law of Demeter)又叫作最少知识原则(The Least Knowledge Principle),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和 陌生人说话。英文简写为: LOD。
-
合成复用原则:尽可能使用组合或者聚合等关系来关联类,其次才考虑使用继承。
前五个合称 SOLID原则(单一职责原则、开放关闭原则、里氏替换原则、接口隔离原则和依赖倒置原则)
mvc框架的生命周期说一下
session与cookie的区别是什么?
为什么session的安全性大于cookie?
session与cookie的应用场景有哪些?
php7新特性
标量类型声明
返回值类型声明
语法糖:null合并运算符,太空船操作符
define允许定义常量数组
匿名类,
新增了一些函数intdiv(),随机函数,
1、php7.0相比于php5.6的新特性 参考:http://php.net/manual/zh/migration70.new-features.php
2、php7.1相对于php7.0的新特性 参考:http://php.net/manual/zh/migration71.new-features.php
3、php7.2相对于php7.1的新特性 参考:http://php.net/manual/zh/migration72.new-features.php
php8新特性
新增联合类型(Union Types);
添加了 WeakMap;
添加了 ValueError 类;
新增的特性大多是语法糖,主要是JIT。
JIT是一种编译器策略,它将代码表述为一种中间状态,在运行时将其转换为依赖于体系结构的机器码,并即时执行,在PHP8中,Zend VM不需要解释某些操作码,并且这些指令将直接作为CPU级指令执行。
IT和opcache区别
要说明opcode cache与JIT的区别,得先明白,字节码,又叫中间码与机器码的区别。简答的说,提升php执行效率,更快了。
参考:鸟哥博客
手写一个单例模式吧
所谓单例模式,即在应用程序中最多只有该类的一个实例存在,一旦创建,就会一直存在于内存中!
单例设计模式常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。
单例模式的编写遵循三私一公,代码如下
<?php
class Database
{
private $instance;
private function __construct()
{
// Do nothing.
}
public static function getInstance()
{
if (!(self::$instance instanceof self)) {
self::$instance = new self();
}
return self::$instance;
}
private function __clone()
{
// Do nothing.
}
}
$a = Database::getInstance();
$b = Database::getInstance();
// true var_dump($a === $b);
php垃圾回收机制
关键词:使用了引用计数器
-
PHP可以自动进行内存管理,清除不需要的对象,主要使用了引用计数。
-
在zval结构体中定义了
ref_count
和is_ref
,ref_count
是引用计数 ,标识此zval被多少个变量引用 , 为0时会被销毁 。is_ref标识是否使用的 &取地址符强制引用。 -
为了解决循环引用内存泄露问题 , 使用同步周期回收算法。
-
当数组或对象循环的引用自身 , unset掉数组的时候 , 当refcount-1后还大于0的 , 就会被当成疑似垃圾 , 会进行遍历 ,并且模拟的删除一次refcount-1如果是0就删除 ,如果不是0就恢复。
参考:https://www.php.net/manual/zh/features.gc.php
php-fpm是什么?
重点:php-fpm是fastcgi的实现。
PHP5.3.3开始集成了php-fpm模块,不再是第三方的包了。
PHP-FPM提供了更好的PHP进程管理方式,可以有效控制内存和进程、可以平滑重载PHP配置。
php-fpm的运行模型?
重点:多进程同步阻塞模式
-
php-fpm是一种master(主)/worker(子)多进程架构模型。
-
当PHP-FPM启动时,会读取配置文件,然后创建一个Master进程和若干个Worker进程(具体是几个Worker进 程是由php-fpm.conf中配置的个数决定)
-
Worker进程是由Master进程fork出来的。
-
master进程主要负责CGI及PHP环境初始化、事件监听、Worker进程状态等等,worker进程负责处理php请 求。
-
master进程负责创建和管理woker进程,同时负责监听listen连接,master进程是多路复用的;
-
woker进程负责accept请求连接,同时处理请求,一个woker进程可以处理多个请求(复用,不需要每次都创建销毁woker进 程,而是达到处理一定请求数后销毁重新fork创建worker进程),但一个woker进程一次只能处理一个请求。
cgi,php-cgi,php-fpm,fastcgi的区别?
cgi
cgi是一个web server与cgi程序(这里可以理解为是php解释器)之间进行数据传输的协议,保证了传递的是标准数据。
php-cgi
php-cgi是php解释器。他自己本身只能解析请求,返回结果,不会管理进程。php-fpm是调度管理php-cgi进 程的程序。
Fastcgi
Fastcgi是用来提高cgi程序(php-cgi)性能的方案/协议。
cgi程序的性能问题在哪呢?"PHP解析器会解析php.ini文件,初始化执行环境",就是这里了。 标准的CGI对每个请求都会执行这些步骤,所以处理的时间会比较长。
Fastcgi会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复劳动,效率自然提高。而且当worker 不够用时,master可以根据配置预先启动几个worker等着;当然空闲worker太多时,也会停掉一些,这样就提 高了性能,也节约了资源。这就是Fastcgi的对进程的管理。
php-fpm
fastcgi是一个方案或者协议,php-fpm就是FastCGI的后端实现,也就是说,进程分配和管理是FPM来做的。官 方对FPM的解释:【Fastcgi Process Manager】【Fastcgi 进程管理器】。 php-fpm的管理对象是php-cgi,他负责管理一个进程池,来处理来自Web服务器的请求。 对于php.ini文件的修改,php-cgi进程是没办法平滑重启的,有了php-fpm后,就把平滑重启成为了一种可能, php-fpm对此的处理机制是新的worker用新的配置,已经存在的worker处理完手上的活就可以歇着了,通过这 种机制来平滑过度的。
php-fpm如何完成平滑重启?
修改php.ini之后,php-cgi进程的确是没办法平滑重启的。
php-fpm对此的处理机制是新的worker用新的配置,
已经存在的worker处理完手上的活就可以歇着了,通过这种机制来平滑过度。
php-fpm和nginx的通信机制是怎么样的?
怎么选定用tcp还是套接字的方式和nginx通信?
tcp方式是面向链接的协议,更稳定。
套接字效率更高,但是限制nginx和php-fpm都在一台服务器。
php-fpm在请求链路的体现,画出来?
php-fpm有几种工作模式?
PHP-FPM进程管理方式有动态(Dynamic)、静态(Static)、按需分配(Ondemand)三种。
动态
会初始化创建一部分worker,在运行过程中,动态调整worker数量,最大worker数受pm.max_children和process.max
- 当空闲进程数小于min_spare_servers时,创建新的子进程,总子进程数小于等于pm.max_children,小于 等于process.max
- 当空闲进程数大于max_spare_servers,会杀死启动时间最长的子进程
- 如果子进程(idle状态)数大于max_children,会打印warning日志,结束处理
- process小于 max_children ,计算一个num,启动num个worker
- 优点:动态扩容,不浪费系统资源
- 缺点:所有worker都在工作,新的请求到来需要等待创建worker进程,最长等待1s(内部存在一个1s的定时 器,去查看,创建进程),频繁启停进程消耗cpu,请求数稳定,不需要频繁销毁
静态
启动固定大小数量的worker,也有1s的定时器,用于统计进程的一些状态信息,例如空闲worker个数,活动 worker个数
- 优点:不用动态判断负载,提升性能
- 缺点:如果配置成static,只需要考虑max_children数量,数量取决于cpu的个数和应用的响应时间,一次启 动固定大小进程浪费系统资源
按需分配
php-fpm启动的时候不会启动worker进程,按需启动worker,有链接进来后,才会启动
连接到来时(只有链接,不没有数据也会创建,telnet也会创建),创建新worker进程,worker进程数的创建收 max_children设置限制,也受限于全局的process.max设置(三种模式都受限此,下文中有全局配置项讲解), 如果空闲时间超过了process_idle_timeout的设置就会销毁worker进程
优点:按流量需求创建,不浪费系统资源, 缺点:因为php-fpm是短连接的,如果每次请求都先建立连接,大流量场景下会使得master进程变得繁忙,浪费cpu,不适合大流量模式
不推荐使用此模式
工作模式 | 特点 |
---|---|
动态 | 均衡优先,适合小内存服务器,2g左右 |
静态 | 性能优先, 适合大内存机器 |
按需分配 | 内存优先,适合微小的内存,2g以下 |
怎么选定php-fpm的worker进程数?
动态建立进程个数
-
N+20% 到 M/m之间
-
N是cpu核数,M是内存,m是每个php进程内存数
静态进程个数
- M/(m*1.2)
- pm.max_requests, 设置最大请求数,达到这个数量以后,会自动长期worker进程,繁殖内存意外增长
cpu密集型的pm.max_children不能超过cpu内核数,但是web服务属于IO密集型的,可以将pm.max_children的值设置大于cpu核数。
注意:PHP程序在执行完成后,或多或少会有内存泄露的问题。这也是为什么开始的时候一个php-fpm进程只占 用3M左右内存,运行一段时间后就会上升到20-30M。所以需要每个worker进程处理完一定的请求后,销毁重 新创建。
php-fpm如何优化?
- 避免程序跑死(hang) 在负载较高的服务器上定时重载php-fpm,reload可以平滑重启而不影响生产系统的php脚本运行,每15分钟reload一次,定时任务如下:
0-59/15 * * * * /usr/local/php/sbin/php-fpm reload
- 合理增加单个worker进程最大处理请求数,减少内存消耗 最大处理请求数是指一个php-fpm的worker进程在处理多少个请求后就终止掉,master进程会重新respawn新 的。该配置可以避免php解释器自身或程序引起的memory leaks。默认值是500,可以修改为如下配置:
pm.max_requests = 1024
- 开启静态模式,指定数量的php-fpm进程,减少内存消耗
说下你最常用的php框架(laravel框架)的生命周期?
怎么理解 依赖注入(DI)与控制反转(Ioc)?
这让我想起了怎么理解nginx正向代理和反向代理...
IOC(inversion of control)控制反转模式;控制反转是将组件间的依赖关系从程序内部提到外部来管理;
DI(dependency injection)依赖注入模式;依赖注入是指将组件的依赖通过外部以参数或其他形式注入;
依赖注入和控制反转说的实际上是同一个东西,它们是一种设计模式,这种设计模式用来减少程序间的耦合。
依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。
-
依赖注入是从应用程序的角度在描述,可以把依赖注入,即:应用程序依赖容器创建并注入它所需要的外部 资源;
-
而控制反转是从容器的角度在描述,即:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要 的外部资源
laravel的控制反转
是通过反射和递归实现的容器,容器作为全局注册表,使用容器的依赖注入做为一种桥梁来解决依赖,使类之间 耦合度更低。
php的弱类型是怎么实现的?
php是通过c语言进行实现,但是c语言为强类型,那php的弱语言类型是通过PHP底层设计了一个zval(“Zend value”的缩写)的数据结构,可以用来表示任意类型的PHP值。通过共同体实现弱类型变量声明。
简单说下对php 底层变量(zval)数据结构的理解
- 变量存储结构 变量的值存储到以下所示zval结构体中。 zval结构体定义在Zend/zend.h文件,其结构如下:
typedef struct _zval_struct zval;
...
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
};
PHP使用这个结构来存储变量的所有数据。和其他编译性静态语言不同,PHP在存储变量时将PHP用户空间的变量类型也保存在同一个结构体中。这样我们就能通过这些信息获取到变量的类型。
zval结构体中有四个字段,其含义分别为:
属性名 | 含义 | 默认值 |
---|---|---|
refcount_gc | 表示引用计数 | 1 |
is_ref_gc | 表示是否为引用 | 0 |
value | 存储变量的值 | 无 |
type | 变量具体的类型 | 无 |
- 变量类型
zval结构体的type字段就是实现弱类型最关键的字段了,
type的值可以为: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一。
从字面上就很好理解,他们只是类型的唯一标示,根据类型的不同将不同的值存储到value字段。
除此之外,和他们定义在一起的类型还有 IS_CONSTANT和IS_CONSTANT_ARRAY。
这和我们设计数据库时的做法类似,为了避免重复设计类似的表,使用一个标示字段来记录不同类型的数据。
常见的设计模式有哪些?
简单说下单例模式,注册树模式,适配模式,策略模式,观察者模式。
单例
//简单工厂模式
//适用场景:创建对象比较少,业务逻辑不太复杂
<?php
//产品
class bike
{
public function product($destination)
{
print_r($destination);
}
}
class car
{
public function product($destination)
{
print_r($destination);
}
}
//工厂
class simpleFactory
{
public function createBike($obj)
{
return new $obj();
}
}
$factory = new simpleFactory();
$bike = $factory->createBike("bike");
$bike->product("hello,bike");
$car = $factory->createBike("car");
$car->product("hello,car");
?>
观察者模式
//观察者模式 //适用场景:订阅者通知 //自己对观察者模式对理解: 需求:有事情变化你要通知我 实现: 1、要通知对人必须在我这里注册,否则我不知道要通知谁。 2、想要获取通知的人必须遵守我的规则,实现我指定的通知事件,不然我没办法统一通知,(比如高考 查分数,只支持电话查询,你非要微信查我肯定通知不到你) 3、事件发生的时候我会逐一通知你们。
<?php
//定义一个事件产生接口
interface obServer
{
public function update($event_info = null);
}
//定义观察者接口
abstract class genEvent
{
private $ob_servers = [];
//增加观察者
public function addObs($ob_server)
{
$this->ob_servers[] = $ob_server;
}
//通知
public function notify()
{
if (!empty($this->ob_servers)) {
foreach ($this->ob_servers as $ob_server) {
$ob_server->update();
}
}
}
}
class obServer1 implements obServer
{
public function update($event_info = null)
{
echo "观察者1 收到执行通知\n";
}
}
class obServer2 implements obServer
{
public function update($event_info = null)
{
echo "观察者2 收到执行通知\n";
}
}
class event extends genEvent
{
//事件触发
public function trigger()
{
$this->notify();
}
}
//实现
$event = new event();
$event->addObs(new obServer1());
$event->addObs(new obServer2());
$event->trigger();
?>
适配器模式
<?php
//定义抽象类
abstract class Toy
{
public abstract function openMouth();
public abstract function closeMouth();
}
//定义dog
class dog extends Toy
{
public function openMouth()
{
echo "Dog open Mouth\n";
}
public function closeMouth()
{
echo "Dog close Mouth\n";
}
}
//cat
class cat extends Toy
{
public function openMouth()
{
echo "Cat open Mouth\n";
}
public function closeMouth()
{
echo "Cat close Mouth\n";
}
}
//红枣狗可以自己判断开关
interface redTarget
{
public function doMouthOpen();
public function doMouthClose();
}
interface greenTarget
{
public function operateMouth($type=0);
}
//组成适配器
class redAdapter implements redTarget
{
private $adaptee;
//初始化对象
public function __construct(Toy $adaptee)
{
$this->adaptee = $adaptee;
}
//委派调用Adaptee的sampleMethod1方法
public function doMouthOpen()
{
$this->adaptee->openMouth();
}
public function doMouthClose()
{
$this->adaptee->closeMouth();
}
}
//组成绿色遥控
class greenAdapter implements greenTarget
{
private $adapter;
//初始化对象
public function __contruct(Toy $adapter)
{
$this->adapter = $adapter;
}
public function operateMouth($type = 0)
{
$type ? $this->adapter->openMouth() : $this->adapter->closeMouth();
}
}
//测试
class testDriver
{
public function run()
{
//实例化玩具狗
$dog = new dog();
$adapter_dog = new redAdapter($dog);
$adapter_dog->doMouthOpen();
$adapter_dog->doMouthClose();
}
}
$test = new testDriver();
$test->run();
注册树模式
<?php
//创建单例
class Single
{
public $hash;
static protected $ins = null;
final protected function __construct()
{
$this->hash = rand(1, 9999);
}
static public function getInstance()
{
if (self::$ins instanceof self) {
return self::$ins;
}
self::$ins = new self();
return self::$ins;
}
}
//工厂模式
class RandFactory
{
public static function factory()
{
return Single::getInstance();
}
}
//注册树
class Register
{
protected static $objects;
public static function set($alias, $object)
{
self::$objects[$alias] = $object;
}
public static function get($alias)
{
return self::$objects[$alias];
}
public static function _unset($alias)
{
unset(self::$objects[$alias]);
}
}
//调用
Register::set('rand', RandFactory::factory());
$object = Register::get('rand');
print_r($object);