php加载php

php文件加密操作流程

不同的PHP调试环境,加密略有差异。下面主要介绍windows下phpstudy2018、xampp及phpstudy-pro三种环境的php文件加密。

01不同环境的通用流程

1.用Virbox Protector对解释器(php-cgi.exe或httpd.exe)加密

2.用DSProtector对php加密

3.用加密后的解释器(php-cgi.exe或httpd.exe)替换原来的解释器

4.重启Apache服务,即可运行程序

02phpstudy2018

1.加密php-cgi.exe

确认环境的php使用版本,打开对应的php环境目录下php-cgi.exe,将php-cgi.exe拖入到Virbox Protector中。

找到php环境目录下php-cgi.exe,将php-cgi.exe拖入到Virbox Protector中,设置加密选项,ds按钮打开,设置密码。

设置完成后,点击保护选中项目,生成两个文件:php-cgi.ssp.exe 和php-cgi.exe.ssp

2.打开DSProtector,对php文件加密。

点击加密选项页面的【打开DSProtector】,配置文件会自动加载生成的php-cgi.exe.ssp,将待加密的1.php拖入进来,点击开始保护,提示成功,php文件保护成功。

1.php加密成功后,会将源文件备份成1.php.bak,1.php则是加密后的文件,可使用编辑器查看1.php的代码变为乱码。

3.替换php-cgi.exe

将加密后生成的php-cgi.ssp.exe,改名为php-cgi.exe,替换原来的php-cgi.exe

4.重启phpstudy

替换php-cgi.exe后,点击重启phpstudy,即可运行加密的php文件

03phpstudy-pro、小皮面板、宝塔面板

与phpstudy2018的加密流程一致,找到使用的php版本的php-cgi.exe,后面流程一致。替换php-cgi.exe后,重启Apache服务。

04XAMPP

使用XAMPP环境的php项目,服务使用apache,需要对httpd.exe进行加密替换。

1.找到apache文件夹下的httpd.exe,加密httpd.exe

将httpd.exe拖入到Virbox Protector中,加密选项处【ds】按钮打开,设置密码,然后点击【保护选中项目】,会生成httpd.exe.ssp 和httpd.ssp.exe.

2.加密php文件

点击【打开DSProtector】,配置文件会自动加载httpd.exe.ssp,将php文件拖入,点击开始保护,提示成功

index1.php加密成功后,会将源文件备份成index1.php.bak,index1.php则是加密后的文件,可使用编辑器查看index1.php的代码变为乱码。

3.替换httpd.exe

将加密后生成的httpd.ssp.exe,改名为httpd.exe,替换原来的httpd.exe

4.重启apache服务

在xampp面板,将Apache服务stop,然后start。即可运行加密后php文件。

05总结

加密后的php可正常运行,不影响网站性能。无法反编译加密后的php文件。

展开
收起

性能优化之PHP优化

在我们平常写代码的过程中,除了数据库的优化,针对与文件的优化,我们还需要对PHP执行优化,当然对于老司机来说,这都是毛毛雨咯~但是毕竟有新手嘛,于是,我整理这么一片文章。(未完待续...)

性能优化之PHP优化

(一):PHP结构

1.字符串

1.1 少用正则表达式能用PHP内部字符串操作函数的情况下,绝对不用正则表达式,因为其效率高过他们。没的说,正则表达式最耗性能。str_replace函数比preg_replace函数要快的多,strtr函数又比str_replace快得多。有没有你漏掉的好用的函数:例如:strpbrk()、strncasecmp()、strpos()、strrpos()、stripos()、strripos()。1.2 字符替换如果需要转换的都是单个字符串的话,那么用strtr函数来转换,而不是数组。$addr = strtr($addr, "abcd", "efgh"); // 建议$addr = strtr($addr, array('a' => 'e', )); // 不建议1.3 压缩大的字符串使用 gzcompress() 和 gzuncompress() 对容量大的字符串进行压缩和解压,再存入和取出数据库。$str = gzcompress('asdasda'); // 压缩字符串var_dump($str); // 打印输出var_dump(gzuncompress($str)); // 解压字符串1.4 echo输出echo字符串用逗号代替点连接符更快些。虽然echo只是一个语言结构,不是真正的函数。但是,他可以把逗号隔开的多个字符串当做“参数”来处理,所以更快些。$str = 'a';$str1 = 'b';echo $str,$str1; //更快些echo $str . $str1; //速度稍慢1.5 尽量用单引号PHP 引擎允许使用单引号和双引号来封装字符串变量,但是它们的速度是有很大的差别的!使用双引号的字符串会告诉 PHP 引擎,首先去读取字符串内容,查找其中的变量,并改为变量对应的值。一般来说字符串是没有变量的,使用双引号会导致性能不佳。最好使用字符串连接,而不是双引号字符串。$output = "This is a plain string"; // 不好的实践$output = 'This is a plain string'; // 好的实践$type = "mixed"; // 不好的实践$output = "This is a $type string";$type = 'mixed'; // 好的实践$output = 'This is a ' . $type . ' string';1.6 使用isset代替strlen在检验字符串长度时,我们第一想法会使用 strlen() 函数。此函数执行起来相当快,因为它不做任何计算,只返回在zval结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数,多多少少会有些慢,因为函数调用会经过诸多步骤,如字母小写化、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用 isset() 技巧加速执行你的代码。例如:$str = 'catlane';if(strlen($str) < 8){ echo 'Str is too short';}if (!isset($str{8})) { echo "Str is too short";}1.7 echo效率高于print因为echo没有返回值,print返回一个整型。注意:echo输出大字符串的时候,如果没有调整就会严重影响性能。打开Apache的mod_deflate进行压缩,或者打开ob_start将内容放进缓冲区,可以改善性能问题。2.语句2.1 最好不要用@用@掩盖错误会降低脚本运行速度,并且在后台有很多额外操作。用@比起不用,效率差距 3 倍。特别不要在循环中使用@。在 5 次循环的测试中,即使是先用error_reporting(0)关掉错误,循环完成后再打开,都比用@快。error_reporting(0); // 设置错误属性为不提示错误for ($i = 0;$i <= 100;$i ++){ // 循环 echo $a; // 输出没有的变量}error_reporting(E_ALL); // 打开错误提示echo $a; // 报错2.2 避免使用魔术方法对于__开头的函数就命名为魔术函数,它们都在特定的条件下触发。这些魔术函数包括:__construct()、__destruct()、__call()、__callStatic()、__get()、__set()、__isset()、__unset()、__sleep()、__wakeup()、__toString()、__invoke()、__set_state()、__clone() 和 __debugInfo()等等。以__autoload() 为例,如果不能将类名与实际的磁盘文件对应起来,将不得不做大量的文件存在判断。而判断文件存在需要磁盘I/O操作,众所周知,磁盘I/O操作的效率很低,因此这才是使得__autoload()机制效率降低的原因。因此,在系统设计时,需要定义一套清晰的、将类名与实际磁盘文件映射的机制。这个规则越简单越明确,__autoload()机制的效率就越高。autoload机制并不是天然的效率低下,只有滥用autoload、设计不好的自动装载函数,才会导致其效率的降低.所以说,尽量避免使用__autoload等魔术方法,有待商榷。2.3 别在循环里用函数例如:在下边的循环当中每次都会用到count()函数,效率大大降低。1.1比1.2要快的多。for ($i = 0;$i < 100000;$i++){ //设置$arr数组 $arr[] = $i;}//1.1 ,用时0.012734174728394for ($i = 0;$i < count($arr);$i++){}//1.2 ,用时0.0060319900512695$len = count($arr);for ($i = 0;$i < $len;$i++){}2.4 使用三元表达式在简单的判断当中,我们尽量使用三元运算符,更简洁,更高效。//用时2.1457672119141echo isset($a) ? $a : '没有$a变量';//用时9.5367431640625if(isset($a)){ echo $a;}else{ echo '没有$a变量';}2.5 使用合适的选择分支语句switch、case好于使用多个if、else if语句,并且代码更加容易阅读和维护。$a = 'catlane';//用时2.145switch ($a){ case 'catlane': echo '这是catlane'; case 'test': echo '这是test'; default : echo '默认';}//用时3.099if($a == 'catlane'){ echo '这是catlane';}else if($a == 'test'){ echo '这是test';}else{ echo '默认';}2.6 屏蔽敏感信息使用 error_reporting() 函数来预防潜在的敏感信息显示给用户。理想的错误报告应该被完全禁用在php.ini文件里。如果用的是共享虚拟主机,php.ini不能修改,最好添加 error_reporting() 函数。放在每个脚本文件的第一行,或者用require_once()来加载,能有效的保护敏感的SQL查询和路径,在出错时不被显示。2.7 不实用段标签 <?不要使用开始标志的缩写形式,你正在使用这样的符号吗<?,应该用完整的<?php开始标签。当然,如果是输出变量,用<?= $value ?>这种方式是鼓励的,可以是代码更加简洁。2.8 纯PHP代码不加结束标签如果文件内容是纯 PHP 代码,最好在文件末尾删除 PHP 结束标记?>。这可以避免在 PHP 结束标记之后万一意外加入了空格或者换行符,会导致 PHP 开始输出这些空白,而脚本中此时并无输出的意图。3.函数3.1 尽量使用PHP内部函数内置函数使用C语言实现,并且经过PHP官方优化,效率更高。3.2 使用绝对路径在include和require中尽量使用绝对路径。如果包含相对路径,PHP会在include_path里面遍历查找文件。用绝对路径就会避免此类问题,解析路径所需的时间会更少。3.3 包含文件尽量不要用require_once和include_once包含文件,它们多一个判断文件是否被引用的过程,能不用尽量不用。量而使用require、include方法代替。3.4 函数快于类方法调用只有一个参数、并且函数体为空的函数,花费的时间等于7-8次$localvar++运算。而同一功能的类方法大约为15次$localvar++运算。3.5 用子类(派生类)方法基类(父类)里面只放能重用的方法,其他功能尽量放在子类(派生类)中实现,子类(派生类)里方法的性能优于在基类(父类)中。3.6 类的性能和其方法数量没有关系新添加10个或多个方法到测试的类后,性能没什么差异。3.7 读取文件内容在可以用file_get_contents()替代file()、fopen()、feof()、fgets()等系列方法的情况下,尽量用file_get_contents()。因为他的效率高得多!3.8 方法不要细分得过多仔细想想你真正打算重用的是哪些代码?3.9 尽量静态化如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍。当然了,这个测试方法需要在十万级以上次执行,效果才明显。其实,静态方法和非静态方法的效率主要区别在内存。静态方法在程序开始时生成内存,实例方法(非静态方法)在程序运行中生成内存。所以,静态方法可以直接调用,实例方法要先成生实例再调用,静态速度很快,但是多了会占内存。任何语言都是对内存和磁盘的操作,至于是否面向对象,只是软件层的问题,底层都是一样的,只是实现方法不同。静态内存是连续的,因为是在程序开始时就生成了,而实例方法申请的是离散的空间,所以当然没有静态方法快。静态方法始终调用同一块内存,其缺点就是不能自动进行销毁,而实例化可以销毁。4.变量4.1 及时销毁变量数组、对象和GLOBAL变量在 PHP 中特别占内存的,这个由于 PHP 的底层的zend引擎引起的。一般来说,PHP数组的内存利用率只有 1/10。也就是说,一个在C语言里面100M 内存的数组,在PHP里面就要1G。特别是,在PHP作为后台服务器的系统中,经常会出现内存耗费太大的问题。4.2 使用$_SERVER变量如果你需要得到脚本执行的时间,$_SERVER['REQUSET_TIME']优于time()。一个是现成就可以直接用,一个还需要函数得出的结果。date_default_timezone_set('PRC');// 设置时区sleep(5);//脚本睡5秒echo date('Y-m-d H:i:s', time());//获取时间戳echo date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']);//获取请求时刻时间戳4.3 方法里建立局部变量在类的方法里建立局部变量速度最快,几乎和在方法里调用局部变量一样快。//用时3.0994415283203function test(){ $a = '这是局部变量输出'; echo $a;}test();//用时4.0531158447266$a = '这是局部变量输出';function test1(){ echo $GLOBALS['a'];}test1();4.4 局部变量比全局变量快由于局部变量是存在栈中的。当一个函数占用的栈空间不是很大的时候,这部分内存很有可能全部命中cache,CPU访问的效率是很高的。相反,如果一个函数同时使用全局变量和局部变量,当这两段地址相差较大时,cpu cache需要来回切换,效率会下降。4.5 局部变量而不是对象属性建立一个对象属性(类里面的变量,例如:$this->prop++)比局部变量要慢3倍。4.6 局部变量而不是对象属性建立一个对象属性(类里面的变量,例如:$this->prop++)比局部变量要慢3倍。4.7 提前声明局部变量建立一个未声明的局部变量,要比建立一个已经定义过的局部变量慢9-10倍。4.8 谨慎声明全局变量声明一个未被任何一个函数使用过的全局变量,也会使性能降低。这和声明相同数量的局部变量一样,PHP可能去检查这个全局变量是否存在。

展开
收起

LAMP之PHP的安装与配置

1.进入src目录,解压php源代码包。

# cd /usr/local/src

# ls

# tar -zxvf php 后面版本信息使用tab键补全

适用于PHP最新版本,请参考PHP官网文档。

编译 PHP 时需要 --enable-fpm配置选项来激活 FPM 支持。

命令:./configure --prefix=/usr/local/php7 --enable-fpm (后面php7可自定义) 后面

2.进入目录,特别注意:需要制定Apache和MySQL的安装目录

问题:如果在编译的过程中,出现临时的终止,需要使用命令make clean清除编译过程中产生的临时文件 # make clean

# cd php 后面使用tab键补全

# pwd 打印

# ./configure --prefix=/usr/local/php --with-apxs2=/usr/local/httpd/

bin/apxs --with-mysql=/usr/local/mysql

3.然后在执行 make 和 make install (只有编译成功后,才执行安装)

make 编译

make install 安装

# make && make install

4.复制php配置文件到lib目录下,修改去除php.ini配置文件后面字符。(mv 修改重命名,cp 复制)

# cp php.ini-development /usr/local/php/lib/

# cd /usr/local/php/lib/

# mv php.ini-development php.ini

# ls 查看

5.配置Apache的httpd.conf文件,以后有.php结尾的文件都交给php模块处理

# cd /etc/httpd

# ls

# vim httpd.conf 使用vim编辑器编辑httpd.conf文件

添加一行代码,以后有.php结尾的文件都交给php模块处理

#AddType application/x-httpd-php .php

6. 重启Apache

# pkill -9 httpd (关闭httpd服务)

# /usr/local/httpd/bin/apachectl start(启动),stop(停止),restart(重启)

7.添加一个php的测试文件,看php模块是否正常加载

8.浏览器测试结果:

展开
收起

配置apache以运行php脚本代码

目标1:

执行如下最简单的php程序(代码):

可见,还不行,于是,需要去配置。

apache的配置文件在哪里?

apache安装目录/conf/httpd.conf

用编辑器打开它:

如下:

这就是apache中的“众多模块”,有的已经,有的没有开启。

“php语言”就是apache中的一个模块——但我们得自己去添加上并进行配置!

分两步:

第1步:添加php语言模块,如下所示:

第2步:设定有php语言包,去执行php后缀的文件(中的脚本代码)

然后,重启apache,重新浏览刚才的php网页,如下:

展开
收起

PHP项目搭建流程

1.项目结构说明

config: 数据库配置和邮件服务器配置需要统一管理,放在config文件夹里

frontend: 前台 home

backend: 后台 admin

2.搭建过程

(1).编码规范说明---非常重要

(2).定义核心启动类---让项目run起来

1. 加载配置: 在使用前准备好配置(预加载),方便程序使用

2. 定义常量: 通过路径常量可以定位到任何的项目内的资源

定义run方法:

framework/core/Application.php

getcwd(): 获取当前工作目录的函数

完成init方法编写:

framework/core/Application.php

注册自动加载:

framework/core/Application.php

完成路由分发

controller=Product&action=index

class_exists: 测试一个类是否存在,第一个参数是类名, 第二个参数是在检查是否调用自动加载函数,默认为true。

实现控制器空间分割

framework/core/Application.php

(3).加载视图

加载html页面,渲染输入。

通过include函数加载视图文件:

定位问题使用chrome的开发工具, f12打开, 火狐使用firebug

(4).定义核心控制器

header(‘Location:http地址’)

(5).载入第三方代码类和辅助函数

载入辅助函数类的编写:

载入第三方代码类

(6).载入数据库模型

模型用来处理业务逻辑的,业务逻辑通过数据库结构体现。

增:insert()

删:delete()

改: update()

查: selectByPk

统计总行数: total()

获取第几页的分页数据: pageRows, 主要在处理数据分页的时候用到

框架执行的上层流程图:

控制器和模型流程介绍:

展开
收起

类的自动加载和自定义自动加载函数PHP

类的自动加载

什么叫做类的自动加载?

当在我们的代码的某行语句中,需要一个类,而该类的定义还没有在这之前的代码中出现的时候,此时,系统就会自动调用一个函数(自动加载函数),在该函数中我们可以写代码来加载类文件。

比如:

<?php

function __autoload( $class_name ){

此时,在这里,我们需要来完成加载B这个类文件的工作。

}

class A{} //这是一个类

$a1 = new A(); //这里没有自动加载的发生,因为A这个类在这之前已经“存在了”。

$b1 = new B(); //这里就可能会发生自动加载。。。

?>

代码演示如下:

自定义自动加载函数

实际上,这个函数:__autoload()属于系统中的自动加载函数,它的名字是固定的,我们只是需要去定义该函数的内部代码,以完成加载类文件的功能。

但:

我们也可以自定义加载函数,而且,这样的化,我们就可以定义多个自动加载函数,具有更大的适应性!

做法如下:

spl_autoload_register(“函数名1”);

spl_autoload_register(“函数名2”);

.....

然后,去定义这些函数。

这样,这些函数就可以具有跟“__autoload()”函数同样的功能了。

系统在需要一个类的时候,就会按上述顺序,依次调用这些函数,直到加载成功该需要的类文件。

举例:

结果:

展开
收起

PHP 7.4 新特新速看,预加载了解一下~

PHP 7.4 ,下一个 PHP 7 较小的发布版,期望在 2019 年 11 月 28 日发布。因此,现在是时候让大家深入了解这个版本添加哪些新特性使 PHP 更快、更可靠。

虽然 PHP 7.4 显著地提升了性能和提高代码可读性,PHP 8 才将会是 PHP 性能真正的里程碑,这在 JIT inclusion 的提案显示已充分证明。

现在去无偿迁移

总之,今天我们将概览 PHP 7.4 最瞩目的特性和性能提升。在继续探索之前,你最好记住以下重要的时间节点:

6 月 6 日:PHP 7.4 Alpha 17 月 18 日:PHP 7.4 Beta 1 – Feature freeze(特性固化)11 月 28 日:PHP 7.4 GA Release你可从 the official RFC page 查看全部新特性和功能。

PHP 7.4 发布日期:

PHP 7.4 将于 2019 年 11 月 28 日发布。这是 PHP 7 的下一个小版本,会再次提升性能,提高代码的可读性和可维护性。

PHP 7.4 有什么新功能?

在这边文章中,我们将讨论 PHP 7.4 最终版本中应该增加一些变化和特性:

抛弃 array_merge :PHP 7.4 在数组表达式中引入了扩展运算符

从 PHP 5.6 开始,参数解析 是一种解析数组并遍历到参数列表中的语法。要解析一个或遍历一个数组,必须以 ...(三个点)作为前缀,如下所示:

functiontest(...$args){var_dump($args);}test(1,2,3);现在 PHP 7.4 的 RFC 建议将这个功能扩展到数组定义中:

$arr=[...$args];扩展操作符在数组表达式 第一个明显的优点是性能。RFC 文档:

扩展操作符应该比 array_merge 性能更好。不仅是因为扩展操作符是一种语言结构,array_merge 是一个函数,还因为可以优化编译常量数组的性能。

扩展操作符一个重要的优点是支持任何可遍历的对象, array_merge 函数只支持数组。

下面是数组表达式中的参数解析示例:

$parts=['apple','pear'];$fruits=['banana','orange',...$parts,'watermelon'];var_dump($fruits);如果你在 PHP 7.3 或更早版本中运行此代码,PHP 将抛出解析错误:

Parse error: syntax error, unexpected '...'(T_ELLIPSIS), expecting ']' in /app/spread-operator.php on line 3相反,PHP 7.4 将返回一个数组:

array(5){[0]=>string(6)"banana"[1]=>string(6)"orange"[2]=>string(5)"apple"[3]=>string(4)"pear"[4]=>string(10)"watermelon"}RFC 声明我们可以多次扩展同一个数组。而且,我们可以在数组中的任何地方使用扩展运算符语法,因为可以在扩展运算符之前或之后添加普通元素。所以,就像下面代码所示的那样:

$arr1=[1,2,3];$arr2=[4,5,6];$arr3=[...$arr1,...$arr2];$arr4=[...$arr1,...$arr3,7,8,9];也可以将函数返回的数组直接合并到另一个数组:

functionbuildArray(){return['red','green','blue'];}$arr1=[...buildArray(),'pink','violet','yellow'];PHP 7.4 输出以下数组:

array(6){[0]=>string(3)"red"[1]=>string(5)"green"[2]=>string(4)"blue"[3]=>string(4)"pink"[4]=>string(6)"violet"[5]=>string(6)"yellow"}我们也可以使用 生成器:

functiongenerator(){for($i=3;$i<=5;$i++){yield$i;}}$arr1=[0,1,2,...generator()];但是我们不允许合并通过引用传递的数组。考虑以下的例子:

$arr1=['red','green','blue'];$arr2=[...&$arr1];如果我们尝试按引用合并数组,则 PHP 会引发以下解析错误:

Parse error: syntax error, unexpected '&' in /app/spread-operator.php on line 3无论如何,如果第一个数组的元素是通过引用存储的,则它们也将通过引用存储在第二个数组中。这是一个例子:

$arr0='red';$arr1=[&$arr0,'green','blue'];$arr2=['white',...$arr1,'black'];这就是我们使用 PHP 7.4 所获得的:

array(5){[0]=>string(5)"white"[1]=>&string(3)"red"[2]=>string(5)"green"[3]=>string(4)"blue"[4]=>string(5)"black"}The Spread operator 提案以 43 票对 1 票获得通过。

箭头函数 2.0 (短闭包)

对于 PHP 而言,匿名函数 被认为十分冗长并且难以使用和维护的。RFC 提出了更短并且语法更简洁的 * 箭头函数(短闭包),能够在很大程度上使我们的 PHP 代码更简洁。

考虑如下例子:

functioncube($n){return($n*$n*$n);}$a=[1,2,3,4,5];$b=array_map('cube',$a);print_r($b);PHP 7.4 允许使用更简洁的语法,上面的函数可以重写为如下:

$a=[1,2,3,4,5];$b=array_map(fn($n)=>$n*$n*$n,$a);print_r($b);目前,要感谢 use 语法,匿名函数 (闭包) 可以从父作用域里继承已经定义的变量:

$factor=10;$calc=function($num)use($factor){return$num*$factor;};但是在 PHP 7.4 中, 在父作用域里定义的变量被隐式捕获(隐式作用域绑定)了。如此一来,我们可用只用一行代码重写整个上面的函数:

$factor=10;$calc=fn($num)=>$num*$factor;我们可以像使用 use(变量) 一样,直接使用在父作用域里定义的变量,并且它也不会修改父作用域的变量。

新的语法对我们构建更可读可维护的代码带来了极大的改善。我们也可以使用参数和返回类型、默认值、变长参数列表(可变函数),可以传递或返回引用等等。然后呢,短闭包还可以被用作类方法,可以像常规一样使用 $this。

RFC 已经以 51 票对 8 票通过了,所以我们可以期待在 PHP 7.4 新增功能里见到它。

空合并赋值操作符

在 PHP 7 中,当我们需要同时使用三元运算符和 isset() 时,合并运算符(??)就可以派上用场了。如果第一个操作数是存在并且不为 NULL,则返回该操作数。否则返回第二个操作数。示例如下:

$username=$_GET['user']??'nobody';这段代码很简单:获取请求参数,如果不存在,则设置一个默认值。它的意思很明确,但如果出现像下方这个来自 RFC 中示例这种更长的变量名呢?

$this->request->data['comments']['user_id']=$this->request->data['comments']['user_id']??'value';从长远的角度看,这段代码可能有点难以维护。因此,为了帮助开发人员编写更直观的代码,这个 RFC 建议引入空合并赋值操作符(??=)。因此,我们可以编写如下代码进行替代:

$this->request->data['comments']['user_id']??='value';如果左侧的参数是 null,则使用右侧参数的值。请注意,当合并运算符是比较运算符时,??= 就是一个赋值运算符。

这项建议以 37:4 的票获得通过。

类型属性 2.0

参数类型声明(或类型提示)允许对将要传递给函数或者类方法的变量类型进行限定。该功能自 PHP 5 起可用,PHP 7.2 起可以使用对象作为数据类型。现在 PHP 7.4 通过添加 类属性类型声明 进一步扩展了类型提示。以下是一个基本的示例:

classUser{public int $id;public string $name;}支持 void 与 callable 以外的所有类型

public int $scalarType;protected ClassName $classType;private?ClassName $nullableClassType;这项 RFC 解释了为什么不支持 void 和 callable 返回值的原因:

不支持 void 类型,因为它没有用到并且语义不明确。不支持 callable 类型,因为其行为取决于上下文。

这样我们就可以安全地使用 bool, int, float, string, array, object, iterable, self, parent, 任何类或接口名称,并且可以为空 types (?type)。

类型可以用于静态属性:

publicstatic iterable $staticProp;也可以使用 var 标记:

var bool $flag;可以设置默认属性值,当然必须与声明的属性类型匹配,但是只有可为空的属性可以具有默认的 null 值:

public string $str="foo";public?string $nullableStr=null;相同类型适用于单个声明中的所有属性:

public float $x,$y;如果我们对属性类型进行错误处理会怎样?考虑以下代码:

classUser{public int $id;public string $name;}$user=newUser;$user->id=10;$user->name=[];在上面的代码中,我们声明了字符串属性类型,但是我们将数组设置为属性值。在这种情况下,我们将收到以下致命错误:

Fatal error: Uncaught TypeError: Typed property User::$name must be string,array used in /app/types.php:9该 RFC 已以 70 票对 1 票获得批准。

弱引用

在这项 RFC 中,PHP 7.4 引入了 WeakReference (弱引用) 类型,这样开发者就可以保留对对象的引用,而这不会阻止对象本身被破坏。

目前,PHP 通过使用诸如 pecl-weakref 之类的扩展名来支持弱引用。无论如何,新的 API 与记录的 WeakRef 类不同。

这是 一份简单的 demo 来自这项提议的作者 Nikita Popov。

$object=newstdClass;$weakRef=WeakReference::create($object);var_dump($weakRef->get());unset($object);var_dump($weakRef->get());第一个 var_dump 打印对象 object(stdClass)#1 (0) {} ,第二个 var_dump 打印引用为 NULL,因为所引用的对象已被销毁。

该 RFC 以 28 票对 5 票获得通过。

协变量返回和协变量参数

方差 是类层次结构的一个属性,描述了类型构造函数的类型如何影响 subtypes。通常,类型构造函数可以是:

Invariant:如果超类型的类型约束子类型的类型。Covariant:如果保留类型的顺序(类型从更具体到更一般)。Contravariant:如果它颠倒了顺序(类型从更通用到更具体地排序)。目前,PHP 的参数和返回类型大部分不变,只有少数例外。该 RFC 建议允许在参数类型和返回类型上进行协方差和协变,并提供一些代码示例。

这是 协变量返回 的一个简单例子:

interfaceFactory{functionmake(): object;}classUserFactoryimplementsFactory{functionmake(): User;}这个是 协变量参数 一个示例:

interfaceConcatable{functionconcat(Iterator $input);}classCollectionimplementsConcatable{// accepts all iterables, not just Iteratorfunctionconcat(iterable $input){/* . . . */}}请参阅 RFC 以更详细地了解 PHP 7.4 协变量返回和协变量参数。

该 RFC 以 39 对 1 票获得通过。

预加载

这项提议 来自 Dmitry Stogov ,这是我们的受支持的提议之一,因为它可以显着提高 PHP 的性能。预加载 是在模块初始化时将库和框架加载到 OPCache 的过程,详细了解 [PHP 生命周期]。

PHP 生命周期 (资源镜像: PHP Internals)

用 Dmitry 的话来说,预加载是这样工作的:

在服务器启动时(在运行任何应用程序代码之前),我们可以将一组 PHP 文件加载到内存中,并使它们的内容 永久可用 给该服务器将服务的所有后续请求。与内部实体完全一样,这些文件中定义的所有函数和类也可用于开箱即用的请求。

这些文件在服务器启动时加载,在任何应用程序之前执行,并且对以后的任何请求均可用。就性能而言,这很棒。

Preloading is controlled by a specific php.ini directive: opcache.preload. This directive specifies a PHP script to be compiled and executed at server start-up. This file can be used to preload additional files, either including them or via the opcache_compile_file() function (read more on PHP documentation).预加载由特定的 php.ini 指令控制:opcache.preload。该指令指定在服务器启动时要编译和执行的 PHP 脚本。此文件可用于预加载其他文件,包括它们或通过 opcache_compile_file() 函数(有关更多信息,请参见 [PHP 文档](https://www.php.net/manual/en/function.opc... -file.php))。

但是有一个缺点。实际上,RFC 里有明确声明:

预加载的文件将永远保留在 opcache 内存中。不重新启动另一台服务器,对其相应源文件的修改将不会生效。

但是,在预加载的文件中定义的所有函数将被永久加载到 PHP 函数和类表中,并且对于以后的每个请求均可用。即使这些改进可能有很大的不同,也会带来良好的性能改进。

您可以在官方的 预加载 RFC 页面 上阅读有关预加载的限制和例外的更多信息。

新的自定义对象序列化机制

这是 Nikita Popov 的另一项提议

当前,我们有两种不同的机制可以在 PHP 中对对象进行自定义序列化:

__sleep() 和 __wakeup() 魔术方法Serializable 接口根据 Nikita 的说法,这两个选项都存在导致复杂且不可靠的代码的问题。您可以在 RFC 中深入研究此主题。在这里我只是提到新的序列化机制应该通过提供两种新的魔术方法__serialize() 和 __unserialize() 来解决这些问题,这两种方法结合了两个现有机制。

该提案以 20 票对 7 票获得通过。

已废弃

PHP 7.4 不推荐使用以下功能。要获得更全面的弃用列表,请查看 PHP 7.4 升级说明。

更改串联运算符的优先级

当前,在 PHP 中,+ 和 - 算术运算符以及 . 字符串运算符保持关联性并具有相同的优先级。(阅读更多相关信息运算符优先级)

例如,考虑以下行:

echo"sum: ".$a+$b;在 PHP 7.3 中,此代码产生以下警告:

Warning:A non-numeric value encountered in /app/types.php on line 4这是因为从左到右评估了串联。与编写以下代码相同:

echo("sum: ".$a)+$b;这项 RFC 建议更改运算符的优先级,给 . 赋予比 + 和 - 运算符低的优先级,以便总是在字符串连接之前执行加法和减法。该行代码应等效于以下内容:

echo"sum: ".($a+$b);这是一个两步建议:

从 7.4 版开始,PHP 在遇到带有 + ,- 和 . 的非括号表达式时应发出弃用通知。这些运算符的优先级的实际更改应在 PHP 8 中添加。两项提议均以绝大多数票获得批准。

弃用左联想三元运算符

在 PHP 中,与许多其他语言不同,三元运算符是左关联的。根据 Nikita Popof 的说法,这对于在不同语言之间进行切换的开发者可能会造成混淆。

当前,在 PHP 中,以下代码是正确的:

$b=$a==1?'one':$a==2?'two':$a==3?'three':'other';解释为:

$b=(($a==1?'one':$a==2)?'two':$a==3)?'three':'other';这可能会导致错误,因为这可能不是我们打算要做的。因此,该 RFC 建议弃用并删除三元运算符的左关联性,并强制开发人员使用括号。

这是另外两个步骤的建议:

从 PHP 7.4 开始,不显式使用括号的嵌套三元将抛出弃用警告。从 PHP 8.0 开始,将出现编译时错误。该提案以 35 到 10 票获得批准。

在 Docker 中安装和运行 PHP 7.4

想在 Docker 上试试吗?幸运的是在 Docker 环境下你不需要再手动编译和配置 PHP 7.4 了 。如果你已经安装了 Docker , 那只需要花几秒钟安装这个非官方的 PHP-FPM 7.4 Docker 镜像 就可以在命令行中进行测试了。

如果你想要运行 PHP 7.4 的代码到你的浏览器中,那你还需要给 Docker 安装 Nginx 或 Apache 镜像。不用担心,只要按照 开发指南。将示例命令拷贝粘贴到命令行中并运行,就可以了。

摘要

在这篇文章中我们简单介绍了 PHP 7.4 发行版大量的更新和新增功能。如果你还想要了解完整的功能列表和正式的 RFC 官方文档,可以参考这些资源:

PHP 7.4 要求说明PHP 7.4 升级说明PHP 7.4 准备任务

展开
收起

使用composer实现php自动加载的一种方式

PHP 的自动加载,之前常用的__autoload和spl_autoload_register,不过最近发现使用composer也可以帮助实现自动加载,也挺好用的,记录一下。

首先需要安装composer

然后在项目根目录创建library和Model目录和一个composer.json文件,在里面输入如下内容:

注:上面内容的library和Model即为自动加载的目录,我们要自动加载的类文件就放在这些目录下。

然后我们在libaray和Model目录下创建两个演示类文件,创建后的目录结构:

User.php的内容:

Hello.php的内容:

index.php里面的内容:

可以看出,我们在Hello类的index方法里调用了User类的info方法,然后我们在index.php里有调用了Hello类的index方法,这时候我们去访问index.php肯定是要报错的,因为我们在调用前并没有引入对应的文件,PHP也不会自动加载。

这时候我们可以打开终端,切换到项目目录下,运行命令:

运行成功后会看到,在项目下生成可一个vendor目录,里面有不少文件,这时候我们只需要把生成的vendor/autoload.php引入到我们的index.php中就行了,index.php的内容修改为:

然后我们再访问index.php,就正常了,借助composer,php文件实现了自动化加载,至于为什么,看看vendor目录下composer帮我们生成的文件就明白了。

目前,越来越多的php框架使用了namesace,用户在使用框架的过程中也未进行直接引入对应的文件,这会给人一种错觉:使用namespace后php会自动加载文件。其实这是错的,框架其实自己实现了一套自动加载机制,用的人没注意而已,一般是通过namespace算出文件的存储路径,然后实例化的时候,会触spl_autoload_register自动加载函数将文件引入。namespace和自动加载是两码事。

展开
收起

php函数-类的动态加载

<?php

function import($file=''){

$file_name = dirname(__FILE__)."/$file".'.class.php';

if(is_file($file_name)){

require $file_name;

$class = new $file();

return $class;

}else{

return false;

}

}

$class = import('abc');

$class->test();

?>

abc.class.php

<?php

class abc{

public function test(){

echo '123';

}

}

?>

展开
收起

PHP文件加载过程

1.文件的路径问题

我们之前也用过一些有关文件路径问题的知识,比如:

<a href=”网页路径” > ....</a>

<img src=”图片路径” />

<script src=”js文件路径” ></script>

php中,有3种路径

相对路径:

有两个特定符号(特定路径)来决定的路径形式:

./ :表示当前目录,也就是当前网页所在的路径

../ :表示当前目录的上一级目录,也就是当前网页所在的目录的上一级目录

相对路径都是由这两个符号开头的路径形式,举例:

include ‘./page1.php’;

include ‘../page2.html’; //也可以载入html文件

include ‘./dir1/dir2/page3.html’;

include ‘../../dir4/dir5/page4.php’;

绝对路径:

就是指:通过该路径,可以不依赖逻辑,而是直接就找到对应文件。

有两种形式的绝对路径:

本地绝对路径:

include ‘c:/dir1/dir2/page1.html’;

include ‘f:/dir3/page3.php’;

特别注意:在代码中,其实千万不要出现上述这种“字面上的绝对本地路径”!!!

实际上,我们需要在代码来“获取”绝对路径,以实现本地文件的绝对路径的加载。

通常,需要使用(以来)如下2个常量,来获取相应的信息:

__DIR__:获取当前网页文件所在的本地绝对路径(目录);

DIRECTORY_SEPARATOR: 它是一个系统常量,表示当前操作系统红的目录之间的分隔符,有:

window系统中,分隔符为:\

linux或unix系统中,分隔符为:/

举例如下:

无指定路径:

形式类似这样:

include ‘page1.html’; //没有给出任何路径信息

include ‘page2.php’;

我们不推荐这样用。

如果万一这样用了,通常php是会在当前网页文件所在位置来找该文件。

2.文件载入详细过程

假设前提:主文件中,有一个载入语句,比如:

include ‘./page1.php’;

则其过程如下:

1,在该语句之前,先“中断”php的代码区域,进入html代码区域;

2,然后,在该语句处,相当于使用被载入的文件内容,替换该载入语句本身!

3,最后,又退出html区域,重新进入php代码区域,继续后续代码。

举例:

它相当于:

展开
收起