PHP
- 貌似基本上的语言都不会像PHP这样,每次一个HTTP请求过来都去重启初始化全部资源(重启整个框架),要解决这个问题,
swoole
是目前最可行的解决方案 - PHP还有一种输出内容模式是直接echo或者直接重定向,在return之前就返回,有些古老的框架是这样的,需要特别注意
- LEMP(Linux + Nginx + MySQL + PHP)环境安装
- 安装多个版本的php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17添加PPA仓库
sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update
安装不同版本PHP
sudo apt install php7.4
sudo apt install php8.1
安装不同版本PHP扩展
sudo apt install php7.4-mbstring php7.4-xml php7.4-mysql
sudo apt install php8.0-mbstring php8.0-xml php8.0-mysql
切换php版本
sudo update-alternatives --config php
验证php版本
php -v
apache切换php版本
sudo a2enmod php7.4
基本语法
判断两个变量是否相等,如果
==
和===
都能用的情况,那么尽量用===
,因为它仅检查闭合范围。??
: null合并运算符。如果遍历那个存在且值不为NULL,就返回本身,否则返回它的第二个操作数。三元运算符可以这样用$a = $a ? : 1
,表示如果为真则直接使用$a
的值,7里面可以写成$a = $a ?? 1
1
2
3$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
$username = $_GET['user'] ?? 'nobody'; // 和上面语句等价
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody'; // 甚至可以连接多个??=
(7.4): 运算符表示有key则赋值,例如$array['key'] ??= 1
表示数组中有key
这个key才会被赋值compact
函数,能够创建一个包含变量和它们的值的数组,例如1
2
3$a = 123;
$b = 'abc';
compact("a", "b"); // ['a' => 123, 'b' => 'abc']
数组
- 7.4支持数组展开操作:
['banana', 'orange', ...$parts, 'watermelon']
,其中$parts
为一个数组
1 | array_column($array, $column_key); // 返回字典型数组里面指定key的那一列组成一个新的数组,取数组指定key组成一个新的数组,例如[['a' => 1], ['a' => 2]], array_column($arr, 'a')得到[1, 2] |
字符串
- 7.1开始支持负数作为偏移:
"abcdefg"[-2] == 'f'
PHP里面单引号和双引号确实有些地方的用法是不同的,比如匹配换行符的时候。我们应该尽量使用单引号,因为如果是双引号,那么程序会去检测其中的变量。
1 | json_decode(string, $assoc=false); # 将字符串转换为json对象,$assoc=true时返回array而不是object |
数字
- PHP_INT_MAX: 最大整数
- PHP_INT_MIN: 最小整数
1 | ceil()函数:向上取整 |
时间
1 | time(): 获取当前时间戳timestamp,秒,10位数 |
Carbon时间处理第三方库
文件/文件夹/目录操作
1 | $fp = fopen("test", "r") or die("Unable to open file!"); # 打开文件 |
函数/类/对象
(array) myobj
对象可强制转换为数组- 创建空对象:
new stdClass()
- 对象转数组:
(array) myClass
- 类的静态常量使用
const
关键字定义 - 7.2开始允许重写抽象方法
- 7.4开始可以给类属性指定类型了,例如:
private int $id;
- 7.4开始支持直接用箭头的简写的匿名函数,例如:
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
1 | # public, private, projtected的区别: |
类的继承
1 | class ChildClass extends ParentClass { |
Type hint
1 | function foo(?Type $a, // 声明参数$a的类型,问号表示可以为null |
发送CURL请求
- 注意使用CURL之前一定要先确定服务器是否已经安装php的curl扩展,如果没有,可能会报奇怪的错误,安装完扩展后记得重启php进程。
- PHP curl中的每一个设置项都有一个唯一的数值与其对应,如果要
var_dump
一个curl
对象,打印出来的就是这些数值,数值都应可以参考https://www.kancloud.cn/baibaoyun/developer/312099
1 | $ch = curl_init(); // 初始化curl |
项目中,强烈推荐使用第三方库Guzzle
,来实现http请求。该库不仅支持curl,而且支持socket等多种底层实现,在没有curl的情况下也可以发送请求,并且实现了发送文件、同步异步等多种方式。
WEB程序
1 | $_SERVER['REQUEST_METHOD'] # 返回数据提交的方式,GET、POST等 |
MySQL
1 | mysql_errno(); # 打印SQL出错信息 |
异常处理
有时候,我们会发现
catch
不到Exception
或者Error
,可能的原因是使用了set_error_handler
等函数进行了错误的单独捕获,还可以使用register_shutdown_function
注册程序退出时候的回调函数7.1开始能够同时捕获多个异常
1
2
3
4
5try {
// some code
} catch (FirstException | SecondException $e) {
// handle first and second exceptions
}error_log
打印日志到php的错误日志中去,配置在php.ini
中的路径
1 | var_dump(debug_backtrace()); # 随时打印当前的调用栈 |
PHP命令行
1 | php --ini # 查看php的配置文件 |
帮助函数
1 | gettype(): 获取变量类型 |
@操作符: 错误控制运算符,写在一行的前面,可以控制改行不输出warning信息或错误信息
**var_dump(变量名)**:打印变量,这个函数还会打印变量的类型可以把一个变量的各个部分全部信息输出,包括每个部分的数据类型和长度等信息,但是默认情况下,输出有限制,如果层数深了或者数据长了可能会表示成省略号,可以在
C:\wamp\bin\apache\\apache2.4.9\bin\php.ini
里面修改xdebug节点,添加如下内容xdebug.var_display_max_children=128
xdebug.var_display_max_data=512
xdebug.var_display_max_depth=5
另外,将var_dump的输出转换为一个字符串以便web前端显示,可以这样用:
ob_start();
var_dump($data);
$result = ob_get_clean();
# 或者用另外的函数
var_export: 输出或返回一个变量的字符串表示file_get_contents:获取文件或http内容,如果要从http获得json数据可以直接使用它
**isset()**:查看某个变量或者多个变量是否已经被定义,未赋值或赋NULL都会返回false。没错,可以直接检查多个变量,当所有变量都为true时返回true
**@header(‘Content-type: text/html;charset=UTF-8’);**PHP文件中添加中文支持,在脚本开始的地方添加给行即可
多行输出:其中最后一个EOF必须写在一行的开头,且里面如果要用变量这样用{ $php_var }
echo <<<EOF
内容
EOF;print_r:打印关于变量的易于理解的信息。如果给出的是 string、integer 或 float,将打印变量值本身。如果给出的是 array,将会按照一定格式显示键和元素。这点在调试的时候很有用
类的方法尽量写成static,速度比public快
composer包管理
--prefer-dist
会下载.zip压缩包,并缓存到本地。--prefer-source
会下载源代码,不会缓存到本地,适合需要修改源代码的时候。--ignore-platform-reqs
表示忽略平台某些依赖的限制,例如ext-zip
的依赖,如果真的不需要就直接在install
的时候加上这个参数吧- 如果
composer
频繁出现.json 404 not found
,那么可以考虑不再使用国内的这个镜像https://packagist.phpcomposer.com
,可以修改镜像地址为:composer config -g repo.packagist composer https://packagist.laravel-china.org
,或者干脆不用国内镜像
require
是指在生产环境中必须的包,而require-dev
则是开发的时候要用而生产环境无需用的包,常用命令:
1 | composer config --list # 列出当前所有的配置 |
composer事件脚本
composer在执行的时候会在时间点上都会抛出相应的事件,可以添加脚本在事件触发后自动执行。例如:pre-install-cmd/post-update-cmd(update命令执行后触发)
,而脚本的定义,可以直接放在composer.json
中,例如一个典型的Laravel
项目的脚本
1 | "scripts": { |
autoload
autoload
,可以预加载类,自动索引所有的类,能够加快依赖的索引速度。但是autoload并不是实时更新的,如果发现vendor/composer/autoload_classmap.php
中的类与你预想的有冲突,那么就需要更新一下了:composer dump-autoload
。
在composer.json
中有四种自动加载类型。PSR的各个规范可以参考PizzaLiu/PHP-FIG:
classmap:
development
相关的1
2
3{
"classmap": ["src/"] # 这样composer就会读取这个文件夹下所有的文件,然后再vendor/composer/autoload_classmap.php中将所有的class的namespace+classname生成一个key=>value的数组
}psr-0: 已经被弃用
psr-4: 一般用于项目代码的自动加载。需要注意的是除去命名空间前缀的其他子命名空间必须和文件目录相对应。子目录里面的命名空间,就把子目录一同写到命名空间中去。
files:
helper
相关的
Extension扩展管理
php的扩展大多可以通过pecl install packagename
直接进行安装(有些库还是需要先安装源文件,再用pecl进行链接),可以使用yum install php-pear
命令安装pecl
工具
1 | var_dump(extension_loaded('curl')); // 查看是否安装某个模块 |
线程/协程/进程
迭代器
PHP的迭代器和其他语言的迭代器用法基本相同。
1 | // 迭代器的while循环 |
PHP配置
配置文件主要放置在php.ini
,在mac上面,php的默认配置在/etc/php.ini.default
,如果需要修改,可以自己新建/etc/php.ini
将需要修改的配置写入其中即可。下面是常见的配置
1 | upload_max_filesize = 2M # 允许上传的文件最大大小 |
另外,在PHP代码中可以这样设置和获取配置
1 | ini_get('upload_max_filesize'); // 但是该属性只能获取,不能在代码里进行设置 |
非常好用的第三方库
TroubleShooting
Call to undefined function getallheaders()
版本问题,如果是老版本可以使用如下代码代替
if (!function_exists('getallheaders')) { function getallheaders() { foreach($_SERVER as $key=>$value) { if (substr($key,0,5)=="HTTP_") { $key=str_replace(" ","-",ucwords(strtolower(str_replace("_"," ",substr($key,5))))); $out[$key]=$value; }else{ $out[$key]=$value; } } return $out; } }
回掉函数中访问外部变量
方法一:使用类的静态变量
方法二:使用use语法
1
2
3$dt->each(function() use($bianliang) {
echo $bianliang;
});Error while reading line from server
这是在使用predis时报的错误,原因是没有设置
read_write_timeout=-1
使redis保持永久连接,否则会在一定时间后断开连接isset
和empty
判断变量是否存在的问题。都不能用于静态数组变量的判断,最好用array_key_exists
PHP调用Dubbo服务: 按照这个教程一步一步来http://www.huangxiaobai.com/archives/1437。
PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 130968 bytes) in …: PHP作为daemon程序运行时候经常性出现内存溢出问题,并且这种错误程序是不会退出的,只会卡在那里,supervisor也不会发现程序的异常。首先检查为什么内存溢出,如果是有大量的curl请求,那么有可能是请求未释放或者curl本身的问题(curl 7.19.7在网上有说是有ssl内存溢出漏洞的)。如果实在想不到,那么可以这样做,使用
memory_get_peak_usage(true)
函数判断当前的内存使用量,当快达到阈值(php.ini中有设置,一般为256MB,top出来显示的内存比这个高一点)的时候,主动退出程序或者退出循环,销毁变量,重新开启循环。可以通过valgrind
来辅助调试内存泄漏问题。
另外在执行composer
的时候也会出现类似的错误,可以这样子执行php -d memory_limit=-1 composer update
直接不限制从数据库取出的整型数据变成了字符串: php5.3之前,php连接mysql的驱动是
libmysqlclient
,5.3开始mysqlnd
内置于PHP中了,新的驱动就不会出现这种情况了Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF environment variable. Then, rerun this script.
yum install autoconf
fatal error: pcre.h: No such file or directory:
yum install pcre-devel/sudo apt-get install libpcre3-dev
PDOException “could not find driver”: 安装
php-mysql/php5-mysql/php7-mysql
扩展Composer报错
Failed to decode response: zlib_decode(): data error
: 出现在更换源之后,这时候应该先执行composer clear-cache
Class ‘Maatwebsite\Excel\Excel’ not found: 尝试升级该依赖
composer require maatwebsite/excel:^3.0.1
PHP实现startsWith和endsWith功能: 不过
Laravel
框架自带了这两个函数的1
2
3
4
5
6
7
8
9
10
11
12function startsWith( $haystack, $needle ) {
$length = strlen( $needle );
return substr( $haystack, 0, $length ) === $needle;
}
function endsWith( $haystack, $needle ) {
$length = strlen( $needle );
if( !$length ) {
return true;
}
return substr( $haystack, -$length ) === $needle;
}pecl安装扩展出现Please reinstall the libzip distribution:
apt-get install libzip-dev / yum install libzip-devel
zlib.h: no such file or directory: 需要先安装:
apt-get install libz-dev -y
Could not scan for classes inside “vendor/google/apiclient/src/Google” which does not appear to be a file nor a folde: 看起来是googleapis/google-api-php-client库升级导致的,有这个路径的最高版本为2.7.2,2.8之后就没有src/Goolge了
class not found: 如果是自己写的某个类没找到可能是没有require进来,我们在使用namespace的时候光用namespace是不够的,namespace只是表明其名称空间,require才能把代码引入进来,之所以我们使用框架不会报错,因为我们在框架的入口之行了
require __DIR__.'/../vendor/autoload.php'
的file_get_contents报错505 HTTP Version Not Supported error: 把请求的url打印出来,多半是
url``没有
encode`Call to undefined function curl_init(): 需要安装
php_curl
扩展:apt install php-curl -y
No valid bower.json was found in any branch or tag of: 尝试给composer添加github access token,上文有提到
PHP安装SOAP扩展/docker容器安装php-soap扩展:
1
2
3
4yum install php-soap # centos系统php-soap扩展
apt-get install php-soap # debian系统安装php-soap扩展
apt-get update -y && apt-get install -y libxml2-dev && apt-get clean -y && docker-php-ext-install soap # docker容器安装php-soap扩展
php -m | grep soap # 查看是否安装完成composer.json丢失: 目前没有一个简单的方法从
composer.lock
或者vendor
反向生成composer.json
,可以尝试这样做:1
2composer init # 初始化一个composer.json出来
composer show --installed # 将列出来的包以及版本一个一个粘贴回去SMTP connect() failed: 可能是端口不对,现在大部分邮件都只支持ssl协议了,端口号一般是465
Call to undefined function imagetypes(): 没有安装gd扩展:
apt-get install libpng-dev && php7.4-gd -y
**ignore_user_abort(false) **: 可以使前端在断开连接后后端仍然能够执行完成
扩展阅读
- DuckChat: 一款独立部署的聊天系统
- WSDL转PHP代码