PHP 学习笔记

1、PHP简史

  1. PHP最初是作为工具包出现。
  2. 1996发布2.0版本,可以访问数据库,还可以把PHP代码嵌入到HTML页面中。
  3. PHP3.0重写了代码,具有强大的可扩展性。
  4. 2000发布4.0,出现Zend引擎,性能提升近10倍。
  5. 2004发布5.0,引入了面向对象、类型提示和异常处理。
  6. 2005年发起的6.0最终被取消,但命名空间、匿名函数、闭包等特性加入到5.x版本。
  7. 2016发布PHP7,性能提升一倍。
  8. 2020发布PHP8,引入JIT 编译、联合类型、属性等,性能提升一倍。

2、PHP程序执行方式

PHP为解释执行,首先将源码编译为opcode指令集合,后PHP虚拟机解释执行opcode。PHP8又引入了JIT编译。PHP程序执行由Zend引擎完成,底层是C语言实现。
在这里插入图片描述
PHP 源码目录:

  • sapi:输入输出层的抽象,常用实现有:
    • apache2handler,编译生成动态链接库,当有http请求到Apache时,根据配置调用此动态链接库,执行PHP代码;
    • cgi-fcgi,编译生成支持CGI协议的可执行程序,通过CGI协议把请求传给CGI进程,执行代码将结果返回,退出进程;
    • fpm-fcgi,FastCGI进程管理器,若使用Nginx,Nginx按照FastCGI协议把请求交给php-fpm进程处理;
    • cli,命令行交互接口;
  • Zend:Zend引擎核心代码,包括编译器、解释器、内存管理、底层数据结构等
  • main:SAPI层和Zend层的黏合剂,解析参数,调用PHP脚本
  • ext:PHP扩展,比如定义了array、str、pdo等函数
  • TSRM:线程安全资源管理器,为每个线程提供独立的全局变量副本

PHP虚拟机架构
在这里插入图片描述
PHP内存管理
在这里插入图片描述

  • 采用了内存池,用于提高内存分配、释放的性能
  • 借鉴了jemalloc和tcmalloc这两个成熟的内存管理方案
  • 垃圾回收为引用计数法

3、变量

PHP变量为弱类型,类型在运行时动态决定,底层由结构体zval表示,占16字节。

$an_int = 12; // 变量声明
  • 四种标量类型
    bool(布尔型):值为 true 或 false
    int(整型)
    float(浮点型,也称作 double)
    string(字符串):二进制安全
  • 四种复合类型
    array(数组):实现为HashTable
    object(对象):属性通过HashTable实现
    callable(可调用):支持简单函数、类的方法、实现__invoke方法的对象
    iterable(可迭代):配合foreach使用,支持array 、Traversable、yield
  • 两种特殊类型
    resource(资源):文件句柄、Socket连接、数据库连接等
    NULL(无类型)
var_dump()  // 表达式的值和类型
gettype() // 表达式的类型
is_int()  // is_type函数,检查类型
$foo = (int) $bar; // 强制类型转换

引用

$a =& $b; // 意味着 $a 和 $b 指向了同一个变量

变量的作用域
局部变量、全局变量、静态变量、常量

智能字符串
smart_str,用于频繁对一个字符串进行扩容修改。

4、数组 array

数组的语义

  • PHP数组是一个字典,存储key-value对,键是整型或字符串。
  • PHP数组是有序的,有序指插入顺序。

数组的实现为Hashtable:
在这里插入图片描述

  • bucket:存储单元,存储key、value、h值等
  • slot:一个slot下可以有多个bucket
  • 冲突解决:链地址法,即将同一个slot中的bucket通过链表连接起来
  • hash1函数:字符串key计算出一个h值,h值为数字,数字key返回数字本身
  • hash2函数:将h值映射为slot的索引值
  • h和key:“h”代表数字key,“key”代表字符串key

数组的数据结构

  • 所有bucket都分配在连续的数组内存中,冲突解决是记录下一个bucket在数组中的索引
  • bucket分为未使用、有效、无效三种。插入操作永远在下一个未使用bucket上进行。删除操作将有效标记为无效。当无效bucket较多时,对整个bucket数组进行rehash操作,一部分有效和无效bucket会被释放出来,重新变为未使用bucket。

packed array 和 hash array

$a = array(1,2,3); // packed array
$b = array('x'=>1, 'y'=>2, 'z'=>3); // hash array
  • packed array
    数组的key即为bucket数组的下标
  • hash array
    数组的key通过hash函数得到索引,再通过索引数组得到所在bucket
    在这里插入图片描述

5、面向对象

class SimpleClass extends BaseClass {
	// 常量
	const CONST_VALUE = 'A constant value';
    // 声明属性
    public $var = 'a default value';
    // 构造方法
    function __construct() {
        parent::__construct();
        print "In SubClass constructor\n";
    }
    // 声明方法
    public function displayVar() {
        echo $this->var;
    }
}
$obj = new SimpleClass();
echo $obj::CONST_VALUE;
echo SimpleClass::CONST_VALUE;

可见性:public(默认)、protected、private
static:静态属性/方法,可以直接通过类访问
final:final方法无法被子类覆盖,final类不能被继承

抽象类和接口

abstract class AbstractClass {
    abstract protected function getValue();
}
interface iTemplate {
    public function setVariable($name, $var);
}

trait
组合的代码复用方式;
当前类的成员覆盖 trait 的方法,而 trait 覆盖被继承的方法;

trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}
// 使用多个trait
class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A; // 同名时使用B的smallTalk 
        B::bigTalk as talk; // B的bigTalk起一个别名
    }
}

匿名类

var_dump(new class(10) {
    private $num;
    public function __construct($num) {
        $this->num = $num;
    }
});

重载
PHP的重载指动态地创建类属性和方法。
重载方法必须声明为 public。

// 以下“不可访问”指未定义或不可见

// 在给不可访问属性赋值时,__set() 会被调用。
public __set ( string $name , mixed $value ) : void
// 读取不可访问属性的值时,__get() 会被调用。
public __get ( string $name ) : mixed
// 当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
public __isset ( string $name ) : bool
// 当对不可访问属性调用 unset() 时,__unset() 会被调用。
public __unset ( string $name ) : void
// 在对象中调用一个不可访问方法时,__call() 会被调用。
public __call ( string $name , array $arguments ) : mixed
// 在静态上下文中调用一个不可访问方法时,__callStatic() 会被调用。
public static __callStatic ( string $name , array $arguments ) : mixed

遍历属性

// 遍历所有可见属性
foreach($objA as $key => $value) {
    print "$key => $value\n";
}

也可以实现 Iterator 接口或 IteratorAggregate 接口,自行决定如何遍历。

魔术方法
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法。

自定义方法建议不要以 __ 为前缀。

对象复制

// 浅拷贝
$copy_of_object = clone $object;

对象比较

  • $o1 == $o2 两个对象的属性和属性值都相等,且是同一个类的实例
  • $o1 === $o2 指向同一个对象

后期静态绑定
用于在继承范围内引用静态调用的类。

class A {
    public static function foo() {
        static::who();
    }
    public static function who() {
        echo __CLASS__." ";
    }
}

class B extends A {
    public static function test() {
        A::foo();
        parent::foo();
        self::foo();
    }
    public static function who() {
        echo __CLASS__." ";
    }
}
class C extends B {
    public static function who() {
        echo __CLASS__." ";
    }
}

C::test(); // 输出 A C C

协变与逆变
协变使子类比父类方法能返回更具体的类型; 逆变使子类比父类方法参数类型能接受更模糊的类型。

6、CGI (Common Gateway Interface)

CGI 是一种数据协议,用来规范web服务器传输到php解释器中的数据类型以及数据格式,包括URL、查询字符串、POST数据、HTTP header等。CGI程序可以由不同语言实现。

PHP Web服务处理请求过程:
在这里插入图片描述
CGI 与 Servlet 的区别:

  • Servlet 处于服务器进程中,它通过多线程方式运行其 service 方法,一个实例可以服务于多个请求,并且其实例一般不会销毁
  • CGI 对每个请求都产生新的进程,服务完成后就销毁,称作 fork-and-execute 模式,效率上低于servlet

因为CGI效率低,但对配置很敏感,通常被用在开发和调试阶段。

FastCGI
FastCGI 是 CGI 的增强版本,主要用来提高CGI程序性能,同样可以由不同语言实现。工作方式:

  1. Web Server启动同时,加载FastCGI进程管理器(nginx的php-fpm或微软IIS的ISAPI或Apache的Module)
  2. FastCGI进程管理器读取php.ini配置文件,对自身进行初始化,启动多个CGI解释器进程(php-cgi),等待来自Web Server的连接
  3. 当Web Server接收到客户端请求时,FastCGI进程管理器选择并连接到一个CGI解释器。Web server会将相关环境变量和标准输入发送到FastCGI子进程php-cgi进行处理
  4. 在Linux中,nginx加php-fpm是最主流的使用方式

PHP SAPI(Server Application Programimg Interface):

  • 相当于PHP外部环境的代理器。PHP可以应用在终端上(CLI SAPI),也可以应用在Web服务器中(CGI SAPI)。
  • 底层实现为 _sapi_module_struct。

Nginx + PHP-FPM 模式

  • FPM(FastCGI Process Manager)是一个FastCGI进程管理器,可以有效控制内存和进程,支持平滑重启PHP及重载PHP配置。
  • FPM是多进程的服务,其中有一个master进程(做管理工作)和多个worker进程(处理数据请求)。
  • 执行过程主要分为5大阶段,分别是模块初始化、请求初始化、执行、请求关闭和模块关闭。由于FPM是常驻内存的进程,所以其模块初始化只做一次,便进入循环,而模块关闭在进程退出时也只做一次。

PHP-FPM 进程有三种设置方式:

  • static:固定数量的worker进程
  • dynamic:设置一个范围,worker进程数动态变化
  • ondemand:worker进程闲置了指定秒数后就会被杀掉

通信示意图:
在这里插入图片描述
在这里插入图片描述

7、控制语句

条件语句
if…elseif…else 、 switch…case

循环语句
while 、 do…while 、 for 、 foreach
break 、 continue

代替语法
把左花括号 { 换成冒号 :,把右花括号 } 分别换成 endif;,endwhile;,endfor;,endforeach; 以及 endswitch;

if ($a == 5):
    echo "a equals 5";
else:
    echo "a is not 5";
endif;

goto:

for($i=0,$j=50; $i<100; $i++) {
	while($j--) {
		if($j==17) goto end; 
	}  
}
echo "i = $i";
end:
echo 'j hit 17';

match:

$expressionResult = match ($condition) {
    1, 2 => foo(),
    3, 4 => bar(),
    default => baz(),
};

8、函数

生成器
yeild

function makeRange($length) {
    for($i = 0; $i < $length; $i++) {
        yield $i;
    }
}
foreach (makeRange(100) as $i) {
    echo $i . PHP_EOL;
}

闭包(匿名)函数

$message = 'hello';

// 继承 $message
$example = function () use ($message) {
    var_dump($message);
};
$example();

箭头函数
匿名函数和箭头函数都是 Closure 类的实现

$y = 1;
// 可以自动捕获变量的值
$fn1 = fn($x) => $x + $y;

var_export($fn1(3));

Callable 类型

// An example callback function
function my_callback_function() {
    echo 'hello world!';
}

// An example callback method
class MyClass {
    static function myCallbackMethod() {
        echo 'Hello World!';
    }
}

// Type 1: Simple callback
call_user_func('my_callback_function'); 

// Type 2: Static class method call
call_user_func(array('MyClass', 'myCallbackMethod')); 

// Type 3: Object method call
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

PHP 8 新特性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值