Skip to content

现代 PHP - PHP 之道 项目学习笔记(总)[未完待续] #65

@huliuqing

Description

@huliuqing

现代PHP

这是 PHP 之道项目学习笔记。

本文除了对项目「PHP 之道」中所阐述的技术外,加入了自己的理解,并修复的部分无效资源链接地址和新增了一些内容

Windows 安装 PHP

@todo

PHP 内置 Web 服务器

自 PHP 5.4 版本器, CLI SAPI 提供内置的 Web 服务器,主要用于本地开发,不可用于线上开发环境。
启动内置 Web 服务器,需要进入项目根目录,执行命令

php -S localhost:3000

代码风格指南

当前还没有官方出品的编码规范,不过 PHP 标准组提出了实践编码标准,也是蛮多 PHP 社区的事实编码标准,在开发过程中遵循这些标准即可

编码标准

@ TODO 阅读规范

编码标准检测工具

PHP_CodeSniffer 工具可以检测代码是否符合这些编码标准,还有 Sublime Text 检测插件,Visual Studio Code 插件

PHP Code Siniffer 简单使用

  1. 安装

全局和局部安装 PHP Code Siniffer 需要确保

  • 已经安装了 PHP
  • 全局安装需已经安装了 PEAR
  • 局部安装需已经安装了 Composer

1.1 全局安装

执行命令安装 PHP Code Siniffer

pear install PHP_CodeSniffer

1.2 局部安装(项目内安装)

执行命令安装 PHP Code Siniffer

composer require --dev squizlabs/php_codesniffer

1.3 PHP_CodeSniffer 基本用法

1.3.1 检测需要修复的文件

phpcs file/to/sniff

# 以 PSR2 规范检测响应需要修复的方法
phpcs -sw --standard=PSR2 file/to/sniff

#

1.3.2 使用 PHP_CodeSniffer 美化修整器

phpcbf -w --standard=PSR2 file/to/sniff

资源

PHP CodeSniffer - 开源项目
PHP CodeSniffer - 开源项目 Wiki

PHP代码规范与质量检查工具PHPCS,PHPMD的安装与配置

PHP 之道 phpcs 使用

编码标准修正工具

PHP 语言精粹

里程碑

  • PHP 5.0 完善面向对象
  • PHP 5.3 新增匿名函数与命名空间
  • PHP 5.4 支持 traits

TODO PHP 面向对象编程

PHP 有用完整的面向对象功能特性

面向对象文档

  1. 抽象类
  2. 接口
  3. 继承
  4. 构造函数
  5. 克隆
  6. 异常

TODO Trait

Trait 文档

函数式编程 (Functional Programming)

PHP 支持函数是 「第一等公民」 ,体现在:

  1. 函数可以赋值给变量(包括内置和用户定义函数都可以赋值给变量)。
  2. 函数可以作为参数传递给其它函数(称为 高阶函数)。
  3. 也可作为函数返回值返回。
  4. 支持递归和迭代。

PHP 函数式编程

TODO PHP 函数式编程

匿名函数

TODO 匿名函数(闭包)文档

Closure 类

Closure 类,及代表匿名函数的类

TODO Closure 类

TODO Closures RFC

Callable 类型

Callable(或 Callback) 类型

动态调用函数方法 call_user_func_array()

文档

语法: mixed call_user_func_array(callable $callback, array $param_array)

$callback: 最为回调函数调用
$param_array: 最为回调函数的参数传入

<?php

function add($arg1, $arg2)
{
    printf("Call function add, add %s + %s\n", $arg1, $arg2);
}

class Add
{
    public function doAdd($arg1, $arg2)
    {
        return $arg1 + $arg2;
        // printf("Call class Add::doAdd, add %s + %s", $arg1, $arg2);
    }
}

call_user_func_array("add", array(1, 2));

$result = call_user_func_array(array(new Add(), "doAdd"), array(3, 4));

var_dump("Call Add::doAdd result:" . $result);

TODO 文档

函数式编程参考资料

TODO

元编程

通过使用反射 API 和魔术函数,可以实现 PHP 的元编程功能。

反射 API

TODO 反射 API

重载

TODO 文档

魔术函数

TODO 文档

命名空间

不同开发者开发的库,可能有使用相同类名的可能,这就导致冲突异常命名空间
的功能引入就是解决该问题。

命名空间类似操作系统的目录,同一目录下不能创建两个同名的文件;同理,两个相同
命名空间内不能创建相同的 PHP 类。

在编写代码时,将代码放在自定义命名空间下,可避免与第三方类库冲突。

命名空间

TODO 文档

PSR-4 标准: 自动加载规范

本规范除定义了自动加载相关内容,还提供了命名空间的推荐使用方式,它提供一个标准的文件、类和命名空间的使用惯例,进而让代码做到随插即用。仔细阅读

PHP 标准库

PHP 标准库(Standard PHP Library 简称 SPL),随 PHP 一起发布,提供一组类和接口。

包含常用的数据结构类(堆栈,队列,堆等),及遍历这些数据接口的迭代器。

TODO PHP 标准库文档

数据结构

TODO 数据结构文档

  1. SplDoublyLinkedList : 双向链表
  2. SplStack: 堆栈
  3. SplQueue: 队列
  4. SplHeap: 堆
  5. SplMaxHeap: 最大堆
  6. SplMinHeap: 最小堆
  7. SplPriorityQueue: 优先队列
  8. SplFixedArray: 定长数组
  9. SplObjectStorage: 类提供从对象到数据的映射,或通过忽略数据来提供对象集

SPL 学习博文

迭代器

TODO 迭代器文档

接口

TODO 接口文档

  1. Todo Countable: 实现该接口可被用于 count() 函数
  2. OuterIterator:实现该接口,可被迭代器迭代
  3. RecursiveIterator: 实现该接口,可被迭代器递归迭代
  4. SeekableIterator:The Seekable iterator

异常

TODO 异常文档

文件处理

TODO 文件处理文档

SPL 函数

TODO SPL 函数文档

其它类与接口

TODO 其它类与接口文档

付费 SPL 视频教程

在这里

命令行接口

PHP 提供命令行接口(CLI),通过 PHP 命令行编程能够帮助完成自动化任务,如测试,部署和应用管理

TODO 命令行选项文档

查看 PHP 版本

php -v

查看 PHP CLI 命令行选项列表

php -h

查看 PHP 配置信息

php -i

功能类似与 phpinfo() 函数

shell 交互式编程

php -a
# response 
# Interactive shell
# php> 

之后可以直接在 SHELL 环境下进行 Interactive shell 编程

php > echo 5 + 8;
13
php > function addTwo($num)
php > {
php { return $num + 2;
php { }
php > var_dump(addTwo(2));
php shell code:1:
int(4)
php >

执行 PHP 脚本

语法:php scriptname.php [param1] [param2] 或者 php -f scriptname.php [param1] [param2]
使用命令,解析并执行 scriptname.php 脚本

$argc: 传递给脚本的参数数目

$argv: 传递给脚本的参数数组

注: 对于 $argc 由于脚本名(如 hello.php) 总是作为参数传递给脚本,因此 $argc 最小值为 1
注: 对于 $argv 由于第一个参数总是当前脚本的文件名(如 hello.php),因此 $argv[0] 就是脚本文件名(如 hello.php)。

举例:创建文件名为 hello.php 的脚本

<?php

if($argc != 2) {
    echo "Usage: php hello.php [name].\n";
}

$name = $argv[1];
echo "hello, $name\n";

执行命令:

php hello.php huliuqing
## or
php -f hello.php huliuqing

# result 
hello, huliuqing

XDebug 调试工具学习

XDebug 是一个 PHP 调试工具,可以在很多 IDE 中做[ TODO 断点调试],[ TODO 堆栈检查],也可以进行代[ TODO 码覆盖检查]和[ TODO 性能跟踪]。

安装 XDebug

使用工具 查找适合安装的 XDebug 版本
工具使用教程

入门 XDebug

使用XDebug和WebGrind工具优化PHP性能

XDebug 远程调试功能

TODO PHP 之道 : XDebug

依赖管理

TODO PHP 之道 : 依赖管理

Composer

Composer

Composer 是 PHP 项目的依赖管理工具,用于管理项目中的 packagies 和 libraries ,使用Composer 安装的依赖库安装与 vendor 目录。

Composer 入门

开发实践

TODO PHP 之道 : 开发实践

基础知识学习

TODO 基础知识

日期和时间函数

TODO PHP 之道 : 开发实践

TODO 日期与时间 文档

TODO DateTime 类
TODO DateInterval 类
TODO DatePeriod 类

使用 Carbon 组件

TODO Carbon

日期格式

设计模式

TODO PHP 之道 : 设计模式

TODO 设计模式

使用 UTF-8 编码

PHP 使用 UTF-8

在 PHP 中对于字符串拼接或赋值操作,并不需要对 UTF-8 做特别处理。

但是如果是对字符串定位如 strpos(),或求字符串长度 strlen() 则需要特别处理。

函数名类似 mb_*TODO 多字节字符串函数就是专门为 Unicode 字符串而特别进行设计。

在编写 PHP 脚本时,应该在脚本开头使用 TODO mb_internal_encoding("UTF-8") 函数设置内部字符编码,并在对浏览器输出显示是使用 TODO mb_http_output() 获取 HTTP 输出字符编码

patchwork/utf8: 该工具会在 mbstring 可用时自动使用,否则自动切换回非 UTF-8 函数。

数据库使用 UTF-8

浏览器使用 UTF-8

在 PHP 内我们保证使用 mb_http_output() 确保向浏览器输出 UTF-8 编码的字符串。

之后,我们可以通过两种方式设置浏览器 UTF-8 编码

  1. 在 HTML 文件的 TODO 字符集 标签
  2. 在 PHP 脚本里设置 Content-Type 响应头

举例

<?php
//告知 PHP 我们在此次使用的是 UTF-8 编码的字符
mb_internal_encoding("UTF-8");

//告知 PHP 我们在输出浏览器时使用 UTF-8 编码
mb_http_output("UTF-8");

// Our UTF-8 test string
$string = 'Êl síla erin lû e-govaned vîn.';
 
// Transform the string in some way with a multibyte function
// Note how we cut the string at a non-Ascii character for demonstration purposes
$string = mb_substr($string, 0, 15);

header('Content-Type: text/html; charset=UTF-8');
?><!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>UTF-8 test page</title>
    </head>
    <body>
        <?php
            echo $string;
        ?>
    </body>
</html>

字符串处理更多资料

TODO

国际化(I18N) 和本地化(L10N)

TODO PHP 之道 : 国际化(i18n)和本地化(l10n)

概念

I18N: internationalization(国际化),指一开始设计一个支持多语言的架构。
L10N: Localization(本地化),指的是新语言的添加。基于 I18N 的架构设计,在每次新增语言时,新增对语言的翻译
Pluralization: 复数形式,不同语言复数规则不一样

TODO 阅读 国际化(i18n)和本地化(l10n) 实现

TODO PHP 之道 : 国际化(i18n)和本地化(l10n)

依赖注入

TODO PHP 之道 : 依赖注入

数据库

TODO PHP 之道 : 数据库

数据库驱动

  1. mysql:5.5 起标记为废弃7.0正式移除
  2. mysqli: MySQL驱动
  3. mssql: 7.0正式移除
  4. pgsql: PostgreSQL数据库驱动
  5. PDO

PDO

TODO PDO 使用教程

什么是 PDO

PDO是一个数据库连接抽象库,通过提供对不同数据库交互的通用接口。

使用模版

TODO PHP 之道 : 使用模版

MVC 软件架构模式中,模版即为「试图(V: View)」,提供了展现逻辑与业务逻辑分离的能力。

为什么使用模版?

  1. 将项目的呈现逻辑与业务逻辑分离,模版完成对内容的展现。
  2. 实现团队分工合作,前端工程师实现前端展现逻辑,服务端工程师实现代码业务逻辑和模型控制
  3. 改善前端架构,模版放在「试图」文件夹内,能够将大块的代码查分称小块的组件实现组件复用。
  4. 能够使用专业的前端模版类库,类库能够提供对用户内容的有效处理,提升项目安全性

原生 PHP 模版

原生 PHP 模版:指在前端页面(通常是 HTML 页面)内混用 PHP 标签,进行混合编程

优点是相对 PHP 研发人员无需学习新的语法,没有编译过程,速度更快;但是会使 前端 HTML 与服务端业务逻辑杂糅在一起,不利于后期维护和开发。

编译模版

尽管 PHP 不断升级为成熟的、面向对象的语言,但它作为模板语言 没有改善多少

广泛使用的编译模版有:

  1. Smarty
  2. TODO Twig

编译模版优点:

  1. 提供专门的模版语法
  2. 自动转义,提供模版继承功能实现复用
  3. 简化控制结构
  4. 提升代码可读性和维护性

编译模版不足,由于需要编译会带来性能上的影响;解决方案为对编译后的文件进行缓存

mustache 语言

TODO mustache

更多资源

文章与教程

Templating Engines in PHP
An Introduction to Views & Templating in CodeIgniter
Getting Started With PHP Templating
Roll Your Own Templating System in PHP
Master Pages
Working With Templates in Symfony 2
Writing Safer Templates

类库

Aura.View (native)
Blade (compiled, framework specific)
Brainy (compiled)
Dwoo (compiled)
Latte (compiled)
Mustache (compiled)
PHPTAL (compiled)
Plates (native)
Smarty (compiled)
Twig (compiled)
Zend\View (native, framework specific)

错误与异常

TODO PHP 之道 : 错误与异常

PHP 是一个「轻异常」(exception light) 语言,当在执行过程中 PHP 会尽量忽略异常,除非遇到严重错误

$ php -a
php> echo $foo;

## throw notice exception
PHP Notice:  Undefined variable: foo in php shell code on line 1

PHP 在上面的例子中将抛出一个 Notce 级别的异常错误,但是 PHP 会继续执行脚本。

常用错误级别

  • Error: 错误异常,将中断脚本执行,必须修复;常量 E_ERROR
  • Notice: 通知异常,建议性的异常信息,脚本不会中断执行;常量 E_NOTICE
  • Warning: 警告异常,非致命的错误,也不会中断执行;常量E_WARNING

修改 PHP 错误报告行为

使用 error_reporting() 函数设置程序在执行期间的错误等级,在程序执行过程中将仅显示
设定的异常消息

<?php
error_reportint(E_ERROR | E_WARNING);

控制错误消息输出方式

除了将错误消息直接输出到屏幕,还可以通过设置将错误消息记录到日志中,请查看 TODO Error Reporting(错误报告)

行内错误抑制

通过错误控制操作符 @ ,可以抑制异常输出

echo @$foo;

但是别这样处理,原因有

  1. 所有的错误都不会输出到屏幕
  2. 所有的错误都不会记录到错误日志

关闭 @

原生 PHP 无法关闭 错误抑制操作符 @,但是可以使用 XDebug 的 xdebug.scream 的 ini 配置项关闭它

xdebug.scream = On

也可是在 PHP 脚本内,运行时设置

<?php
ini_set("xdebug.scream", 1);

此外,还可以通过 Scream 来设置

资料

错误异常类

通过使用 ErrorException 类抛出 「错误」来处理异常,该类继承自 Exception 类。

资料

异常

在开发过程中使用 try{}catch(Exception $d){} 来抛出和捕捉异常处理

SPL 异常

通过继承 SPL 标准库 Exception 类处理异常操作

资料

安全

TODO PHP 之道 : 安全

Web 程序安全

密码 Hash 处理

什么是 Hash 算法

Hash 密码算法是单向不可能的,Hash 值是固定长度的字符串切无法推算出原始密码。

在构建 Web 应用程序或其它应用程序,最终会加入用户授权模块,这涉及到用户帐号及密码存储功能。

对密码应该单独

  1. 存储密码前进行密码 Hash 处理
  2. 使用加盐处理,以防(「字典破解」)(https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwjiurrX0v7VAhXCGJQKHbRrBMQQFggmMAA&url=https%3A%2F%2Fzh.wikipedia.org%2Fzh-hans%2F%25E6%259A%25B4%25E5%258A%259B%25E7%25A0%25B4%25E8%25A7%25A3%25E6%25B3%2595&usg=AFQjCNGO3NW2bTMVI_fOd1sRsBskPXesrQ)或(「彩虹碰撞」)(https://zh.wikipedia.org/zh-hans/%E5%BD%A9%E8%99%B9%E8%A1%A8)

PHP Hash 密码算法函数 password_hash()

  1. password_hash() 创建密码的 Hash,在生成 Hash 值时函数已经处理好加盐,加入的随机子串通过加密算法自动保存, 自 PHP 5.5 引入
  2. password_verify() 来验证密码是否匹配 password_hash 生成的 hash 值

对于 PHP 5.3.7

资料

数据过滤

永远不要相信外部输入

对以下数据来源

  1. $_GET 表达你数据
  2. $_POST 表单数据
  3. $_SERVER 获取的超全局变量
  4. fopen("php://input", 'r') 得到的 HTTP 请求体
  5. 上传和下载的文档
  6. session 值
  7. cookie 值
  8. 第三方 Web 服务数据

都需要使用 filter_var()filter_input(),对数据进行过滤处理

过滤策略

  1. 原始的外部数据传入到 HTML 页面输出,可能引发 XSS 攻击。 解决方法是,在输出前使用 strip_tags() 去除 HTML 标签 或 使用 htmlentities() 或 htmlspecialchars() 函数对特殊字符进行转义得到特殊字符的 HTML 实体
  2. 对由命令行传入的数据,使用 escapeshellarg() 函数进行过滤
  3. 通过接收外部输入来从文件系统加载文件。可已过滤调 /, ../null字符或其它敏感的、私有的、需要隐藏的文件

数据清理

数据清理:指删除或转义外部输入中的非法或不安全的字符。

  1. 对外部输入数据包含在 HTML 标签中的数据进行过滤
  2. 对使用原始 SQL 语句进行插入请求的数据进行过滤
  3. 对允许使用的可靠 HTML 标签采用白名单库进行校验,可以使用类似 TODO HTML Purifier 白名单库
  4. 除了使用白名单库,可以使用 TODO MarkdownTODO BBCode 这些更严格的规则进行过滤
资源

TODO 查看 安全过滤器文档(Sanitization Filters)

有效性验证

对用户输入的 email 地址,手机号,年龄等等信息进行有效性校验;可以使用 TODO 校验过滤器

反序列化 Unserialization

对不可信渠道的序列化数据进行反序列化可能存在安全问题

TODO Is PHP unserialize() exploitable without any 'interesting' methods?
TODO PHP Object Injection

配置文件安全

策略:

  1. 配置文件不要存储在可直接访问或上传的目录
  2. 配置文件如果一定要存放于根目录,请以 .php 文件扩展进行重命名,这样即使可以访问也无法直接输出显示
  3. 对配置文件中信息进行加密或设置访问权限
  4. 密钥等敏感数据不要加入到版本控制中

关闭注册全局变量功能

PHP 5.4 以前如果在配置选项值中开启 register_globals 功能,可以是 $_GET, $_POST, $_REQUEST, $_COOKIE 等变量被注册为全局变量

比如 $_GET['foo'] 被注册后可直接通过 $foo 访问到,这将是不安全的。

另一个例子是:

<?php
// 当用户合法的时候,赋值 $authorized = true
if (authenticated_user()) {
    $authorized = true;
}

// 由于并没有事先把 $authorized 初始化为 false,
// 当 register_globals 打开时,可能通过GET auth.php?authorized=1 来定义该变量值
// 所以任何人都可以绕过身份验证
if ($authorized) {
    include "/highly/sensitive/data.php";
}
?>

TODO 在 PHP 手册中了解 Register_globals

测试

TODO PHP 之道 : 测试

单元测试

单元测试是一种编程方法来确认函数,类和方法以我们预期的方式来工作,单元测试会贯穿整个项目的开发周期。通过检查各个函数和方法的输入输出,你就可以保证内部的逻辑已经正确执行。通过使用依赖注入和编写”mock” 类以及 stubs 来确认依赖被正确的使用,提高测试覆盖率。

工具:

atoum
Kahlan
Peridot
SimpleTest

集成测试

集成测试 (有时候称为集成和测试,缩写为 I&T)是把各个模块组合在一起进行整体测试的软件测试阶段。它处于单元测试之后,验收测试之前。集成测试将已经经过了单元测试的模块做为输入模块,组合成一个整体,然后运行集成测试用例,然后输出一个可以进行系统测试的系统。

功能性测试

功能测试的工具

Selenium
Mink
Codeception 是一个全栈的测试框架包括验收性测试工具。
Storyplayer 是一个全栈的测试框架并且支持随时创建和销毁测试环境。

行为驱动开发

@todo

其他测试工具

@todo

服务器与部署

TODO PHP 之道 : 服务器与部署

PaaS

Platform as a Service (PaaS): 提供运行服务端项目所必须的系统环境和网络架构,仅需要项目做少量配置即可运行。

虚拟或专用服务器

Nginx 和 PHP-FPM

PHP 通过内置的 FastCGI 进程管理器(PHP-FPM)与 Nginx 服务器进行交互

资料

TODO 阅读更多 nginx 的内容
TODO 阅读更多 PHP-FPM 的内容
TODO 学习如何配置安全的 nginx 和 PHP-FPM

Nginx 和 PHP-FPM

@todo

共享主机

构建及部署应用

@ TODO

在对项目进行修改或更新的时候,我们都需要将更新重新部署新版本项目到服务器才行,这样即使一个简单的更新都需要做大量的操作

我们需要自动化构建或持续集成工具,协助完成部署工作

自动化或持续集成的任务主要体现在:

  1. 依赖管理
  2. 对静态资源的编译和压缩
  3. 执行测试
  4. 生成文档
  5. 打包
  6. 部署
构建自动化工具

@todo

自动化构建工具,及通过一系列的脚本完成项目的部署通用任务,它独立于项目之外。

  1. Phing 是一种在 PHP 领域中最简单的开始自动化部署的方式。通过 Phing 你可以控制打包,部署或者测试,只需要一个简单的 XML 构建文件。Phing (基于Apache Ant) 提供了在安装或者升级 web 应用时的一套丰富的任务脚本,并且可以通过 PHP 编写额外的任务脚本来扩展

  2. Capistrano 是一个为 中高级程序员 准备的系统,以一种结构化、可复用的方式在一台或多台远程机器上执行命令。对于部署 Ruby on Rails 的应用,它提供了预定义的配置,不过也可以用它来 部署 PHP 应用 。如果要成功的使用 Capistrano ,需要一定的 Ruby 和 Rake 的知识。

对 Capistrano 感兴趣的 PHP 开发者可以阅读 Dave Gardner 的博文 PHP Deployment with Capistrano ,来作为一个很好的开始。

  1. Rocketeer 从 Laravel 框架中得到了很多灵感。 目标是默认智能化配置、高速、优雅的自动化部署工具。他支持多服务器,多阶段,并行部署等功能。工具的扩展性极强,并且是由 PHP 编写。

  2. Deployer 是一个用 PHP 编写的部署工具,它很简单且实用。并行执行任务,原子化部署,在多台服务器之间保持一致性。为 Symfony、Laravel、Zend Framework 和 Yii 提供了通用的任务脚本。推荐阅读 Younes Rafie 的博文 快速使用 Deployer 部署 PHP 应用

  3. Magallanes 是另一个由 PHP 编写的自动化部署工具。使用 YAML 作为配置信息,支持多服务器和多环境,自动化部署。并且自带了许多通用的任务。

延伸阅读:

服务器布置 Server Provisioning

@todo

持续集成

@todo

虚拟化技术

TODO PHP 之道 : 虚拟化技术

缓存

TODO PHP 之道 : 缓存

代码注释

TODO PHP 之道 : 代码注释

PHPDoc

@todo PHPDoc 文档

资源

TODO PHP 之道 : 资源

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions