PHP Development Guide

PHP 开发指引

安装

Rocky 9

# NOT RECOMMAND
dnf module switch-to php:remi-7.4
dnf module switch-to php:remi-8.2
dnf remove php-xml php-mbstring php-fpm php-common php-cli php-json

# Recommand to use alternatives for PHP version managing
alternatives --install /usr/bin/php php /usr/bin/php74 1
alternatives --install /usr/bin/php php /usr/bin/php82 2
## Selete effective PHP interpreter.
alternatives --config php

Enterprise Linux

# EL 7Remi's RPM repository
sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
sudo yum -y --enablerepo=epel,remi,remi-php7 install php-fpm php-cli php-gd php-mbstring php-mcrypt php-mysqlnd php-opcache php-pdo php-devel

# EL9
sudo yum install http://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf install -y php74-php-fpm php74 php74-php-opcache php74-php-pecl-redis5 php74-php-mysqlnd php74-php-devel php74-php-mbstring php74-php-soap php74-php-pecl-zip php74-php-xml php74-php-pecl-mcrypt php74-php-pecl-yaml php74-php-pecl-apcu php74-php-pear php74-php-pgsql php74-php-gd
sudo alternatives --install /usr/bin/php php /usr/bin/php74 1

# wp 命令行
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
# PHP 7.0.x from IUS
sudo yum install mod_php70u php70u-mysqlnd php70u-pecl-redis php70u-xml php70u-gd php70u-devel php70u-mbstring php70u-opcache php70u-pdo php70u-pear php70u-soap

macOS

Brew 可以安装多个版本的 PHP 环境。

命令 作用
brew install php@7.3 安装 PHP 7.3
brew install shivammathur/php/php@7.4
brew-php-switcher 7.3 切换 /usr/local/bin 下连接的 php 环境

Brew 安装后的指示: 

To enable PHP in Apache add the following to httpd.conf and restart Apache:
    LoadModule php7_module /usr/local/opt/php@7.4/lib/httpd/modules/libphp7.so

    <FilesMatch \.php$>
        SetHandler application/x-httpd-php
    </FilesMatch>

Finally, check DirectoryIndex includes index.php
    DirectoryIndex index.php index.html

The php.ini and php-fpm.ini file can be found in:
    /usr/local/etc/php/7.4/

php@7.4 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have php@7.4 first in your PATH, run:
  echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
  echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc

For compilers to find php@7.4 you may need to set:
  export LDFLAGS="-L/usr/local/opt/php@7.4/lib"
  export CPPFLAGS="-I/usr/local/opt/php@7.4/include"


To restart php@7.4 after an upgrade:
  brew services restart php@7.4
Or, if you don't want/need a background service you can just run:
  /usr/local/opt/php@7.4/sbin/php-fpm --nodaemonize

Ubuntu

凭借第三方安装源 Ubuntu 可实现多版本 PHP 共存。

export LC_ALL=C.UTF-8
sudo add-apt-repository ppa:ondrej/php
sudo add-apt-repository ppa:ondrej/nginx           # Stable
sudo add-apt-repository ppa:ondrej/nginx-mainline  # New Features
sudo add-apt-repository ppa:ondrej/apache2

# https://launchpad.proxy.ustclug.org 国内代理
# PHP 7.0
sudo apt install php7.0 php7.0-mbstring php7.0-mysql php7.0-opcache php7.0-json php7.0-xmlrpc php7.0-readline php7.0-zip php7.0-gd php7.0-bcmath php7.0-gd php7.0-fpm php7.0-curl php7.0-cli php7.0-xml php7.0-mcrypt
# PHP 7.1
sudo apt install php7.1 php7.1-mbstring php7.1-mysql php7.1-opcache php7.1-json php7.1-xmlrpc php7.1-zip php7.1-bcmath php7.1-gd php7.1-fpm php7.1-curl php7.1-cli php7.1-xml php7.1-mcrypt php-redis
# PHP 7.2
sudo apt install php7.2 php7.2-mbstring php7.2-mysql php7.2-opcache php7.2-json php7.2-xmlrpc php7.2-zip php7.2-bcmath php7.2-gd php7.2-fpm php7.2-curl php7.2-cli php7.2-xml php-tokenizer php-redis
# PHP 7.3
sudo apt install php7.3 php7.3-mbstring php7.3-mysql php7.3-opcache php7.3-json php7.3-xmlrpc php7.3-zip php7.3-bcmath php7.3-gd php7.3-fpm php7.3-curl php7.3-cli php7.3-xml php-tokenizer php-redis
# PHP 7.4
sudo apt install php7.4 php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-json php7.4-xmlrpc php7.4-zip php7.4-bcmath php7.4-gd php7.4-fpm php7.4-curl php7.4-cli php7.4-xml php-tokenizer php-redis
# 切换默认 PHP 版本
update-alternatives --config php
# Apache2 + PHP 默认版本 @ Ubuntu 16.04
sudo apt install libapache2-mod-php php7.0 php7.0-mbstring php7.0-mysql php7.0-xmlrpc php7.0-readline php7.0-zip php7.0-gd php7.0-bcmath php7.0-gd php7.0-curl php7.0-cli php7.0-xml php7.0-mcrypt php7.0-fpm php-redis
# Nginx 完整版
sudo apt install nginx-extras

MAMP

安装 pecl 扩展

MAMP 支持多个版本的 PHP 引擎,安装扩展时需要先用 export 调整 PATH 来调整默认的 PHP 版本:

export PATH=/Applications/MAMP/bin/php/php7.0.26/bin:$PATH
pecl install redis

 装完扩展后在 MAMP 中编辑对应的 PHP 配置模版激活扩展:

extension=redis.so

常用命令

示例 作用
sudo update-alternatives --config php 配置命令行 PHP 版本
php -r 'print_r(get_defined_constants());' 运行命令行传入的 PHP 脚本
php -S 0.0.0.0:8088 启动内置 http 服务

常用设置

路径缓存

缓存 PHP 文件的真实路径:

realpath_cache_size = 256k

OPcache

; 是否侦测文件改动:生产环境设为 0,开发环境设为 1
opcache.validate_timestamps = 0

; 每隔多少秒检查文件是否跟新,0 表示每次请求都检查文件是否改动
opcache.revalidate_freq = 0

; PHP 7.0+ 最高支持 100000 10 万
opcache.max_accelerated_files = 100000

opcache.memory_consumption = 64
opcache.interned_strings_buffer = 16
opcache.fast_shutdown = 1

常见错误

未找到 autocconf

$ pecl install redis
WARNING: channel "pecl.php.net" has updated its protocols, use "pecl channel-update pecl.php.net" to update
downloading redis-4.2.0.tgz ...
Starting to download redis-4.2.0.tgz (235,569 bytes)
.................................................done: 235,569 bytes
25 source files, building
running: phpize
Configuring for:
PHP Api Version:         20151012
Zend Module Api No:      20151012
Zend Extension Api No:   320151012
Cannot find autoconf. Please check your autoconf installation and the
$PHP_AUTOCONF environment variable. Then, rerun this script.

解决方案

brew install autoconf

PHP 应用服务器

mod_php

使用 Apache 服务器,为每个请求生成嵌入 mod_php 解释器的子进程。

php-fpm

使用 nginx 服务器,转发 PHP 请求给一系列 php-fpm 进程。

php-fpm.conf

# 一分钟内出现 10 个僵尸子进程则重启主进程
emergency_restart_threshold = 10
emergency_restart_interval = 1m

# 超长相应日志路径
slowlog = LOG_PATH
request_slowlog_timeout = 10s

# Drupal@8G 内存
pm.max_children = 51
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4

调试

php-fpm 运行后可以用 cgi-fcgi 进行调试:

# 可用 CGI 环境变量
# DOCUMENT_ROOT	The root directory of your server
# HTTP_COOKIE	The visitor's cookie, if one is set
# HTTP_HOST	The hostname of the page being attempted
# HTTP_REFERER	The URL of the page that called your program
# HTTP_USER_AGENT	The browser type of the visitor
# HTTPS	"on" if the program is being called through a secure server
# PATH	The system path your server is running under
# QUERY_STRING	The query string (see GET, below)
# REMOTE_ADDR	The IP address of the visitor
# REMOTE_HOST	The hostname of the visitor (if your server has reverse-name-lookups on; otherwise this is the IP address again)
# REMOTE_PORT	The port the visitor is connected to on the web server
# REMOTE_USER	The visitor's username (for .htaccess-protected pages)
# REQUEST_METHOD	GET or POST
# REQUEST_URI	The interpreted pathname of the requested document or CGI (relative to the document root)
# SCRIPT_FILENAME	The full pathname of the current CGI
# SCRIPT_NAME	The interpreted pathname of the current CGI (relative to the document root)
# SERVER_ADMIN	The email address for your server's webmaster
# SERVER_NAME	Your server's fully qualified domain name (e.g. www.cgi101.com)
# SERVER_PORT	The port number your server is listening on
# SERVER_SOFTWARE	The server software you're using (e.g. Apache 1.3)

SCRIPT_NAME=/ \
HTTP_HOST=www.moha.online \
SCRIPT_FILENAME=WEB_ROOT/index.php \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect /run/php/php7.0-fpm.sock

发布

Capistrano

安装及配置

# 在本地环境安装
gem install capistrano

# 项目目录下执行
cap install
文件 作用
config/deploy.rb 如何发布应用:目标路径、Repo 等
config/deploy/*.rb 环境相关信息

常用命令

# 发布
cap production deploy

# 回滚
cap production deploy:rollback

测试

行为驱动开发(BDD)

种类 说明
SpecBDD 人类语言编写单元测试:phpspec
StoryBDD 描述业务逻辑,不涉及实现;整体测试:Behat

PHPUnit

一个测试用例对应一个从 PHPUnit_Framework_TestCase 扩展的类;类中每个以 test 为前缀的方法为一个测试。测试中使用断言诊断是否通过测试,有些断言没有文档,需查源码。

# 安装 PHPUnit 到 vender/bin/phpunit
composer require --dev phpunit/phpunit
常用命令行开关 作用
-c 指定 phpunit.xml 位置
--coverage-text 生成文字覆盖度报告
--coverage-html 指定覆盖度报告保存路径,依赖 XDebug

PHPUnit 用 phpunit.xml 预定义命令行参数:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php">
    <testsuites>
        <!-- 多个测试用例构成一个测试组件 -->
        <testsuite name="whovian">
            <directory suffix="Test.php">tests</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist>
            <directory>src</directory>
        </whitelist>
    </filter>
</phpunit>

bootstrap.php 用来加载 composer 组件:

<?php
// Enable Composer autoloader
require dirname(__DIR__) . '/vendor/autoload.php';
断言 作用
assertAttributeEquals 测试对象属性
@expectedException 注释断言,期待异常

项目根目录准备 .travis.yml 整合 Travis CI 自动测试服务:

# 要小写
language: php
php:
  - 5.4
  - 5.5
  - 5.6
  - hhvm
install:
  - composer install --no-dev --quiet
script: phpunit -c phpunit.xml --coverage-text

性能分析

基准测试工具 Apache Bench 和 Siege 可被用来分析应用性能。Xdebug 可以在开发环境中做性能分析,分析结果需要用 KCacheGrind 或 WinCacheGrind 来查看。XHProf 可以用在开发或生产环境,收集的信息较少,结果用 XHGUI 来查看。

Xdebug

Xdebug 报告为格式为 CacheGrind,mac 中可通过 brew install qcachegrind 安装查看器。

; php.ini 中 Xdebug 的配置

; 避免 Xdebug 生成大量报告
xdebug.profiler_enable = 0

; 用 XDEBUG_PROFILE=1 URL 参数激活
xdebug.profiler_enable_trigger = 1

xdebug.profiler_output_dir = PATH_OF_REPORT

安装

pecl install xdebug-3.1.6 # PHP 7.4

3.x 配置

[xdebug]
xdebug.mode = debug
xdebug.client_host = 127.0.0.1
xdebug.client_port = 9003
xdebug.discover_client_host = true
xdebug.start_with_request = yes

XHProf

XHProf 通过 XHGui 应用管理和配置。

安装

# Ubuntu
sudo apt-get install build-essential;

# CentOS
sudo yum groupinstall 'Development Tools';

sudo pecl install mongo;
sudo pecl install xhprof;

配置

; php.ini 配置相关扩展
extension=xhprof.so
extension=mongo.so
# config/config.default.php 配置 XHProf 触发概率
# 开发环境每次触发
'profiler.enable' => function() {
    return true; // <-- Run on every request
},”

# 生产环境 1% 概率触发
'profiler.enable' => function() {
    return rand(0, 100) === 42;
},”

触发

PHP 应用引入 XHGui 触发 XHProf:

; php.ini 中引入 
auto_prepend_file = /var/sites/xhgui/external/header.php

; nginx 配置中引入
fastcgi_param PHP_VALUE "auto_prepend_file=/var/sites/xhgui/external/header.php";

; Apache 配置中引入
php_admin_value auto_prepend_file "/var/sites/xhgui/external/header.php

在线工具 

Author: njun
njun's picture
Updated: 2023/09/08