PHP小知识点

基础东西

CLI

  • CLI模式下运行PHP代码的三种方式:

    • 运行文件:

      1
      php source.php
    • 直接运行php代码:

      1
      php -r 'phpinfo()';
    • 交互模式

      1
      php -a #进入交互模式

CGI模式

  • 啥是CGI?

    • 简单来说:
      • 背景:早期Web服务器都只能响应静态资源,为了使服务器能直接运行动态脚本,即解决Web服务器和外部应用程序(CGI程序)之间的数据交互,出现了CGI(Common Gateway Interface,通用网关接口)
      • 简单理解:CGI是Web服务器和运行在其上的应用程序进行“交流”的一种约定
    • 具体可以看这个文章,带着如下问题去看可以:CGI是什么
      • CGI如何实现数据的输入输出
      • CGI 的的缺点?
      • 如果使用Apache作为web服务器,是如何调用php解释器的?为什么每次修改php.ini文件都需要重启Apache呢?
      • FastCGI和CGI啥关系?一句话概括下是啥?
      • FastCGI和PHP-FPM啥关系?
      • PHP-FPM创建多个CGI子进程,当有请求进入时,怎么分配谁处理?如果有CGI嘎掉了,FPM管不管?
      • Swoole和FPM区别在哪?举个栗子?
  • 4种PHP Web环境的配置

    • 内置Web服务器:5.4.0以上的版本内置了个服务器,默认的Web根目录是当前目录,-t显式指定Web根目录

      1
      2
      3
      4
      5
      $ php -S localhost:8000 -t ~/www
      PHP 7.1.19 Development Server started at Wed Jan 23 15:11:37 2019
      Listening on http://localhost:8000
      Document root is /Users/david/www
      Press Ctrl-C to quit.
    • 集成开发环境:XMAPP,集合了如下软件的安装包

      • X:支持跨平台
      • A:Apache
      • M:MySQL或MariaDB
      • P:PHP
      • P:Perl
    • LNMP:Linux、Nginx、MySQL、PHP

    • Docker

预定义常量和变量作用域

  • 预定义常量:
名称 说明
$GLOBALS 引用全局作用域种可用的全部变量
$_SERVER 服务器和执行环境信息
$_GET HTTP GET 变量
$_POST HTTP POST 变量
$_FILES HTTP 文件上传变量
$_REQUEST HTTP Request 变量
$_SESSION Session变量
$_ENV 环境变量
$_COOKIE HTTP Cookies

$_SERVER包含信息:

image-20230611020957038

  • 作用域:

    • 文件域:定义在两个不同文件的变量,其作用域限制在文件内部

      1
      2
      3
      # 文件a.php中定义了$a
      <?php
      $a = 1;
      1
      2
      3
      4
      # 文件b.php引入a.php,此时a.php中的 $a对于b.php是不可访问的
      <?php
      include a.php
      var_dump($a); // $a = NULL
    • 函数域:定义在函数内部的变量,其作用域限制在函数内部

      例如函数foo里定义了$a=1,但其生效范围仅限于函数foo里,所以函数foo之外的$a=NULL

    • 全局变量:全局变量可以在任意地方生效,上表中的PHP数据类型里的预定义变量就是全部变量

      可以使用global来改变变量的作用域

常量

  • 常量定义之后,值无法改变,且不能被unset掉

  • 定义方式:

    • define

      1
      defind('FOO', 'foo');
    • const

      1
      const FOO = 'foo';
  • PHP定义的一些魔术变量:

    名称 说明
    __LINE__ 此语句在文件中的当前行号(可能因为include等,行号与单文件不一致)
    __FILE__ 此语句所在文件的完整路径和文件名
    __DIR__ 此语句文件所在的目录
    __FUNCTION__ 此语句所在的函数名称
    __CLASS__ 此语句所在的类名称
    __TRAIT__ 此语句所在Trait名称(trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能)
    __METHOD__ 类的方法名
    __NAMESPACE__ 当前命名空间的名称

循环控制

  • break跳出循环。break可以接受一个可选的数字参数来决定跳出几重循环
  • continue跳过本次循环,不再执行continue之后的剩余代码。continue也可以接受一个参数来决定跳过几重循环到结尾。

可变长度参数

image-20230611015104613

数组

  • PHP的数组除了传统意义的数组(如C语言里的数组)外,还可以起到链表、队列、栈、map的作用
  • 数组分为两种,其一是纯数组,其下标为数字,叫作压缩数组(packed array);其二是哈希数组(hash array),类似于其他语言的map

类和对象

  • PHP的类是单继承的,即最多只能有一个父类。可以实现多个接口,用逗号来分隔多个接口的名称11

    image-20230611015223519

异常处理

  • PHP5中异常处理的流程是try…catch…finally。
  • PHP7中引入了一个与Exception同级别的结构Error,将一些Fatal Error当作Error异常抛出。这种Error异常也可以像Exception异常一样被第一个匹配的try/catch块所捕获。如果没有匹配的catch块,则调用异常处理函数(事先通过set_exception_handler()注册)进行处理。如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)

例如:

image-20230611015352612

命名空间

  • 命名空间是一种对类的层级结构的一种封装方式,类似于操作系统的目录。在不同的命名空间下,用户不用担心类/函数/常量的名字冲突,在引入第三方类库时,也不用担心名字冲突

数据类型

10种数据类型:

  • 4种基本类型:布尔、整形、浮点、字符串
  • 4种复合类型:数组、对象、回调函数、迭代器
  • 2种特殊类型:资源(Resource)、NULL

其他类型转换为bool

image-20230611015613321

PHP整形数值常量

image-20230611015642090

浮点型

  • 浮点型(float或double)表示的变量属于实数的集合。在C语言里,float和double是不同的类型,但在PHP语言里,两者没有区分,都是float类型。PHP的浮点数采用IEEE二进制浮点数算术标准(IEEE 754),通常最大值是1.8e308并具有14位十进制数字的精度(64位IEEE格式)
  • 一般来说,对于64位的双精度数字,只有前15位的有效数字是有意义的,这保证了最大误差一般不大于10-16

字符串

  • string有4种表示方法:单引号、双引号、heredoc、nowdoc

image-20230611015803987

  • 字符串所能表示的最大长度是多少?

    PHP 7之前的版本(5.x),string所能表示的最大长度为2GB。PHP 7之后,字符串就没有这种限制了。出现这种情况的原因,是因为PHP底层对于字符串设计的改变。

    image-20230611015840685

  • 注意:

    • 对于Java、PHP等语言,字符串每次赋值都会生成临时字符串,造成内存浪费

回调函数

  • 回调函数(callbacks)类型可以将一个函数作为变量或参数传递给其他函数使用。在PHP中,诸如call_user_func、call_user_func_array、usort、uasort、uksort等函数,都可以接收一个函数作为参数
  • call_user_func()和call_user_func_array()区别
    • call_user_func()函数不支持引用参数,而call_user_func_array()支持引用参数
    • 参数数目不同。call_user_func可以接收多个参数,包括可变数量的参数;而call_user_func_array可接收一个数组作为参数

迭代器

  • 迭代器是啥?
    • 迭代器(Iterable)是PHP 7.1引入的一种新的数据类型,可用于数组或其他实现Traversable接口的对象,主要用于遍历内部元素。迭代器最多的用处是foreach和yield(生成器相关)

Resource

  • image-20230611020435390

NULL

  • NULL是一种特殊的值,表示变量没有值。判断一个变量是否为NULL,仅有三种可能:
    • 一个变量从未被赋值过。
    • 主动给变量赋值为NULL。
    • 对变量使用unset。

isset和empty区别

  • isset判断一个变量是否被设置或非null,即如果不是null就返回true,否则返回false。判断变量为null的方法就是上面所讲的3种情况。
  • empty判断一个变量是否为0、0.0、空字符串、null、false、空数组等,若是则返回true,否则返回false

变量

指针和引用

  • 在C语言里,指针是一个强大的存在,它可以通过传递指针的方式,将一个变量或函数的内存地址传递出去。直接操作内存是一个高效行为,但过于危险和不可控制,所以在一些语言,如Java、PHP等,不允许直接传递指针,而采用变量引用的方式来实现

  • PHP的变量引用,是指不同的变量访问同一变量的内容,语法为&+变量名。例如,将$a的引用赋值给$b,即$a和$b指向同一个“地址”,当任何一个变量变化时,都会影响到另一个变量

  • 引用的取消:可以用unset来取消其引用,即销毁引用变量

    image-20230611020723545

  • foreach引用陷阱

    image-20230611020756183

image-20230611020809750

  • 结合上图,我们分析一下为什么出现这种情况。
    • 第2行,定义的数组[1,2],如图3-3所示的第1步。
    • 第3至5行,将数组的每个元素都加1,所以$nums = [2,3],同时数组的第2个元素引入了$num的引用。这造成了后面的意想不到的情况。第2个foreach处理第1个元素时,$num被赋值为2,同时$num又和第2个元素共享地址,所以第2个元素的值由3变为2。第2个foreach处理第2个元素时,$num被赋值为2,同时$num又和第2个元素共享地址,相当于把变量本身的值重新赋值给自己,所以第2个元素的值仍然为2。综上所述,$nums变为了[2,2]。
    • 究其原因,是由于数组最后一个元素的$num引用在foreach循环之后仍会保留。建议使用unset()来将其销毁
  • 解决方案:
    • 方法1:不使用变量引用,而用$nums[$index]取出要改变的元素
    • 方法2:既然第1个和第2个foreach的变量名相等,那么不妨将第2个foreach的变量更名为$num2,就规避了变量引用的问题,也能输出正确的结果
    • unset调引用变量
    • 也可使用函数式编程解决

垃圾回收机制

  • 带着问题来吧:
    • 什么样的变量会被回收?
    • 什么时机进行回收操作?
    • 回收步骤是什么?
    • 垃圾回收机制解决什么问题?

回收规则

  • 变量回收的基本规则
    • 变量引用计数增加(被使用或被引用),就不会被回收‘
    • 引用计数减少到零,所在变量容器将被清除(free),直接清理不用进入回收机制
    • 仅仅在引用计数减少到非零值时,才会产生垃圾周期(garbage cycle),可能会被回收

回收时机

image-20230611021209877

回收步骤

  • 模拟删除。根缓冲区(root buffer)里的每个变量zval的refcount减1

  • 模拟恢复。如果refcount不为0,则refcount加1;如果为0,则不加1

  • 真的删除。删除所有refcount为0的zval

机制特性

  • 垃圾回收机制首先是可解决内存泄漏和循环引用问题的(如回收时机的例子2)。注意,并不是每次refcount减少时都进入回收周期,只有根缓冲区满额后在开始垃圾回收。这是性能与功能的tradeoff。其次是将内存泄漏控制在一个阈值以下