======php.8.2=============
PHP8.2 解决了 PHP 类型系统的几个缺点和限制,允许 PHP 应用采用更好的类型安全。包括添加了 true 类型,允许 null 和 false 作为独立的类型使用,并支持 DNF 类型(泛型解析)。 PHP8.2 支持分离范式类型,现在可以进行组合联合类型和交际类型,这可以定义声明精确而富有表现力的参数、返回值和属性。 php8.2 之前 class Foo { public function bar(mixed $entity) { if ((($entity instanceof A) && ($entity instanceof B)) || ($entity === null)) { return $entity; } throw new Exception('Invalid entity'); }} 现在 class Foo { public function bar((A&B)|null $entity) { return $entity; }} 支持 true 和 false 作为独立的类型,如果 bool 始终相同的时候可以用它来声明。 function alwaysReturnsFalse(): false {}function alwaysReturnsNull(): null {}function alwaysReturnsTrue(): true {} 其中 null 的类型在之前的版本中就可以在联合类型声明中使用,现在可以独立使用了。 只读类 PHP8.1 增加了一个 readonly 的属性声明。一个 readonly 的属性只能设置一次,并且 PHP 会阻止任何作用域内的修改。 PHP8.2 对 readonly 声明进行更进一步的使用,可以将类声明为 readonly。当一个类被声明为 readonly,它的所有属性都会自动声明 readonly。此外,这个类不能使用动态属性,以确保所有的属性都是有定义的。 readonly class User { public string $username; public string $uid;} 所有的属性都会自动声明城 readonly。 新的随机数扩展 在 PHP 的历史发展中,它支持各种各样的随机数生成器,他们有不同程度的性能和不同的用例,并且适合安全应用程序。PHP8.2 更进一步,将所有与随机数相关的功能重构为一个名为 random 的扩展。新的扩展不会破坏任何现有的接口使用,因此现有的 rand,mt_rand 函数将继续工作,不需要任何更改。它还提供了一个对象接口,用可插拔的体系生成随机数,因此很容易模拟随机数生成器并提供新的随机数生成器,从而市 PHP 应用程序安全且易于测试。 trait 常量 在 PHP8.2 中,可以在 trait 中声明常量。trait 不能直接访问,但当类使用 trait 时,这些常量就变成了类的常量。 trait Foo{ public const CONSTANT = 1;}class Bar{ use Foo;}var_dump(Bar::CONSTANT); // 1var_dump(Foo::CONSTANT); // Error 敏感参数支持 PHP8.2 新增了一个内置参数属性命名:#[\SensitiveParameter]。能够使 PHP 在堆栈跟踪和错误消息中隐藏掉实际值。 我们经常会在参数或属性中定义密码、秘钥或其他敏感信息。当 PHP 发生错误时,这些值会被记录下来。显示到屏幕上或者记录到日志中。这样人们就能通过这些方式得到敏感数据。 比如下面的例子: function passwordHash(#[\SensitiveParameter] string $password) { debug_print_backtrace(); } passwordHash('hunter2'); 打印的内容如下: array(1) {[0]=> array(4) { ["file"]=> string(38) "..."["line"]=> int(9)["function"]=> string(3) "foo" ["args"]=> array(1) { // [0]=> string(38) "hunter2" 这一行不会被打印出来 [0]=> object(SensitiveParameterValue)#1 (0) {}} }} hunter2 不会被打印出来。 新的函数和类 解析 INI 数量值:ini_parse_quantity 将 PHP ini 值识别成字节。 ini_parse_quantity('256M'); // 268435456 curl 维持活动:curl_upkeep 在 PHP8.2 中,curl 扩展会触发底层 curl 库来运行必要任务,以保持 curl 连接存活。最常见的用法就是定期调用 curl_upkeep 来实现 http 持久连接(keep-alive)。 检索密码长度:openssl_cipher_key_length 在 PHP8.2 OpenSSL 中,有一个名为 openssl_cipher_key_length 的函数,能够接受任何支持的密码所需的秘钥长度,在之前需要硬编码才能实现: openssl_cipher_key_length("CHACHA20-POLY1305"); // 32openssl_cipher_key_length("AES-128-GCM"); // 16openssl_cipher_key_length("AES-256-GCM"); // 32 重置记录的峰值内存使用量:memory_reset_peak_usage 这对于多次调用或迭代调用时很有用。 PHP8.2 中的弃用 PHP8.2 也带来了相当一部分的弃用。当语法、函数和特性被弃用时,PHP 会发起一个弃用通知,该通知不应该中断 PHP 程序,但会被记录到错误日志中。 注意:PHP8.0 以后,PHP 的默认错误报告行为是 E_ALL 已弃用动态属性 PHP8.2 中最值得注意的弃用之一就是弃用动态属性。如果一个类属性没有声明就被调用或赋值,就会退出程序。 class User { public int $uid;}$user = new User();$user->name = 'Foo'; 这个可能会影响到很多的的 PHP 遗留程序,推荐的修复方法是在类型中声明属性。 对此也有例外用法,比如 stdClass 和它的子类将正常使用,__get 和__set 魔术方法将正常使用,或者声明 #AllowDynamicProperties。
===========php8.1=========
=======================Php8.1============ 让我们首先介绍PHP 8.1中的所有新特性。这是一个相当多的清单。 注意:随着PHP 8.1发布日期的临近,此列表可能会增加或缩小。我们将致力于使其保持最新状态。 纯交集类型 枚举 永不返回类型 Fibers 新的只读属性 定义最终类常量 新的fsync()和fdatasync()函数 新的array_is_list()函数 新的Sodium XChaCha20函数 新的IntlDatePatternGenerator类 支持AVIF图像格式 新的$_FILES:目录上传的full_path键 对字符串键控数组的数组解包支持 显式八进制数字表示法 MurmurHash3和xxHash哈希算法支持 DNS-over-HTTPS (DoH) 支持 使用CURLStringFile从字符串上传文件 新的MYSQLI_REFRESH_REPLICA常量 使用继承缓存提高性能 一流的可调用语法 纯交集类型 PHP 8.1添加了对交集类型的支持。它类似于PHP 8.0 中引入的联合类型,但它们的预期用途恰恰相反。 为了更好地理解它的用法,让我们回顾一下PHP中类型声明的工作原理。 本质上,您可以向函数参数、返回值和类属性添加类型声明。这种分配称为类型提示,并确保值在调用时是正确的类型。否则,它会立即抛出一个TypeError。反过来,这可以帮助您更好地调试代码。 但是,声明单一类型有其局限性。联合类型通过允许您声明具有多种类型的值来帮助您克服这个问题,并且输入必须至少满足声明的类型之一。 另一方面,RFC将交集类型描述为: “交集类型”需要一个值来满足多个类型约束而不是单个约束。 …纯交集类型使用语法 T1&T2&… 指定,可用于当前接受类型的所有位置… 请注意使用&(AND) 运算符来声明交集类型。相反,我们使用|(OR) 运算符来声明联合类型。 在交集类型中使用大多数标准类型将导致永远无法满足的类型(例如整数和字符串)。因此,交集类型只能包括类类型(即接口和类名)。 以下是如何使用交集类型的示例代码: 复制 class A { private Traversable&Countable $countableIterator; public function setIterator(Traversable&Countable $countableIterator): void { $this->countableIterator = $countableIterator; } public function getIterator(): Traversable&Countable { return $this->countableIterator; } } 在上面的代码中,我们将变量countableIterator定义为两种类型的交集:Traversable和Countable。在这种情况下,声明的两种类型是接口。 交集类型也符合已用于类型检查和继承的标准PHP变化规则。但是还有两个关于交集类型如何与子类型交互的额外规则。您可以在其 RFC 中阅读有关交集类型差异规则的更多信息。 在某些编程语言中,您可以在同一个声明中组合联合类型和交集类型。但是PHP 8.1禁止它。因此,它的实现被称为“纯”交集类型。但是,RFC 确实提到它“留作未来范围”。 枚举 PHP 8.1终于添加了对枚举(也称为枚举或枚举类型)的支持。它们是用户定义的数据类型,由一组可能的值组成。 编程语言中最常见的枚举示例是布尔类型,具有true和false两个可能的值。它是如此普遍,以至于它融入了许多现代编程语言。 根据RFC,PHP 中的枚举首先将被限制为“单元枚举”: 此RFC的范围仅限于“单元枚举”,即枚举本身就是一个值,而不是简单的原始常量的花哨语法,并且不包括附加的相关信息。此功能极大地扩展了对数据建模、自定义类型定义和 monad 样式行为的支持。枚举启用了“使无效状态不可表示”的建模技术,这会导致更健壮的代码,而无需进行详尽的测试。 为了达到这个阶段,PHP团队研究了许多已经支持枚举的语言。他们的调查发现,您可以将枚举分为三类:花式常量、花式对象和完整代数数据类型 (ADT)。这是一个有趣的阅读! PHP 实现了“Fancy Objects”枚举,并计划在未来将其扩展到完整的ADT。它在概念和语义上都模仿了Swift、Rust和Kotlin中的枚举类型,尽管它没有直接模仿它们中的任何一个。 RFC使用一副牌中著名的西装类比来解释它是如何工作的: 复制 enum Suit { case Hearts; case Diamonds; case Clubs; case Spades; } 在这里,Suit枚举定义了四个可能的值:Hearts、Diamonds、Clubs和Spades。您可以直接访问使用语法这些值:Suit::Hearts,Suit::Diamonds,Suit::Clubs,和Suit::Spades。 这种用法可能看起来很熟悉,因为枚举是建立在类和对象之上的。它们的行为相似并且具有几乎完全相同的要求。枚举与类、接口和特征共享相同的命名空间。 上面提到的枚举称为Pure Enums。 如果您想为任何情况提供标量等效值,您还可以定义支持枚举。但是,支持的枚举只能有一种类型,int或者string(永远不会)。 复制 enum Suit: string { case Hearts = 'H'; case Diamonds = 'D'; case Clubs = 'C'; case Spades = 'S'; } 此外,支持枚举的所有不同情况都必须具有唯一值。你永远不能混合纯枚举和支持枚举。 RFC进一步深入探讨了枚举方法、静态方法、常量、常量表达式等等。涵盖所有这些超出了本文的范围。您可以参考文档以熟悉它的所有优点。 never 返回类型 PHP 8.1添加了一个名为never. 在 alwaysthrow或exit. 根据它的RFC,URL重定向函数总是exit(显式或隐式)是其使用的一个很好的例子: 复制 function redirect(string $uri): never { header('Location: ' . $uri); exit(); } function redirectToLoginPage(): never { redirect('/login'); } 一个never-declared函数应满足三个条件: 它不应该有return明确定义的语句。 它不应该有return隐式定义的语句(例如if-else语句)。 它必须以exit语句(显式或隐式)结束其执行。 上面的URL重定向示例显示了never返回类型的显式和隐式用法。 在never返回类型共享与许多相似之处void返回类型。它们都确保函数或方法不返回值。但是,它的不同之处在于执行更严格的规则。例如,void-declared 函数仍然可以return没有显式值,但您不能对never-declared 函数执行相同的操作。 根据经验,void当您希望 PHP 在函数调用后继续执行时,请继续执行。never当你想要相反的时候就去吧。 此外,never定义为“bottom”类型。因此,任何声明的类方法never都“never”不能将其返回类型更改为其他类型。但是,您可以使用void-declared 方法扩展never-declared 方法。 info: 原始RFC将never返回类型列为noreturn,这是两个PHP静态分析工具(即Psalm和PHPStan)已经支持的返回类型。由于这是由Psalm和PHPStan的作者自己提出的,因此他们保留了其术语。但是,由于命名约定,PHP团队对noreturn vs never进行了民意调查,never最终成为永远的赢家。因此,对于PHP 8.1+版本,始终使用never代替noreturn. Fibers 从历史上看,PHP代码几乎一直是同步代码。代码执行暂停,直到返回结果,即使是 I/O 操作。您可以想象为什么这个过程可能会使代码执行速度变慢。 有多种第三方解决方案可以克服这一障碍,允许开发人员异步编写PHP代码,尤其是并发 I/O 操作。一些流行的示例包括amphp、ReactPHP和Guzzle。 但是,在PHP中没有处理此类实例的标准方法。此外,在同一个调用堆栈中处理同步和异步代码会导致其他问题。 Fibers是PHP通过虚拟线程(或绿色线程)处理并行性的方式。它试图通过允许 PHP 函数中断而不影响整个调用堆栈来消除同步和异步代码之间的差异。 以下是RFC的承诺: 向PHP添加对Fibers的支持。 引入一个新的Fiber类和对应的反射类ReflectionFiber。 添加异常类FiberError和FiberExit来表示错误。 Fibers允许现有接口(PSR-7、Doctrine ORM等)的透明非阻塞I/O实现。那是因为占位符(promise)对象被消除了。相反,函数可以声明I/O结果类型,而不是无法指定解析类型的占位符对象,因为PHP不支持泛型。 您可以使用Fibers开发全栈、可中断的PHP函数,然后您可以使用这些函数在PHP中实现协作多任务处理。当Fiber暂停整个执行堆栈时,您可以放心,因为它不会损害您的其余代码。 图表说明了使用Fibers的PHP代码执行流程。 为了说明Fibers的用法,它的RFC使用了这个简单的例子: 复制 $fiber = new Fiber(function (): void { $value = Fiber::suspend('fiber'); echo "Value used to resume fiber: ", $value, "\n"; }); $value = $fiber->start(); echo "Value from fiber suspending: ", $value, "\n"; $fiber->resume('test'); 你在上面的代码中创建了一个“fiber”,并立即用字符串挂起它fiber。该echo声明用作fiber恢复的视觉提示。 您可以通过调用$fiber->start()检索此字符串值。 然后,使用字符串“test”恢复fiber,该字符串是对Fiber::suspend()的调用返回的。完整代码执行会产生如下输出: 复制 Value from fiber suspending: fiber Value used to resume fiber: test 这是PHP Fibers工作的准系统教科书示例。这是执行七个异步GET请求的另一个Fibers示例。 尽管如此,大多数PHP开发人员永远不会直接处理Fibers。RFC甚至提出了同样的建议: Fibers是大多数用户不会直接使用的高级功能。此功能主要针对库和框架作者,以提供事件循环和异步编程 API。Fibers允许在任何时候将异步代码执行无缝集成到同步代码中,而无需修改应用程序调用堆栈或添加样板代码。 Fiber API不应直接在应用程序级代码中使用。Fibers提供了一个基本的、低级别的流控制API来创建更高级别的抽象,然后在应用程序代码中使用这些抽象。 考虑到它的性能优势,您可以期待PHP库和框架能够利用这一新特性。看看他们如何在他们的生态系统中实施Fibers会很有趣。 新的readonly属性 PHP 8.1添加了对readonly属性的支持。它们只能从它们被声明的作用域初始化一次。初始化后,您永远无法修改它们的值。这样做会引发错误异常。 RFC写道: 一个只读属性只能使用一次,并且只能从已申报范围的初始化。对该属性的任何其他分配或修改都将导致Error异常。 这是一个如何使用它的示例: 复制 class Test { public readonly string $kinsta; public function __construct(string $kinsta) { // Legal initialization. $this->kinsta = $kinsta; } } 一旦初始化,就再也回不去了。将此功能融入PHP会大大减少通常用于启用此函数的样板代码。 readonly属性在类内部和外部都提供了强大的不变性保证。中间运行什么代码并不重要。调用readonly属性将始终返回相同的值。 但是,readonly在特定用例中使用该属性可能并不理想。例如,您只能将它们与类型化属性一起使用,因为没有类型的声明是隐式的null,不能是readonly。 此外,设置readonly属性不会使对象不可变。该readonly属性将保存相同的对象,但该对象本身可以更改。 此属性的另一个小问题是您无法克隆它。已经有针对此特定用例的解决方法。如有必要,请查看它。 定义final类常量 从PHP 8.0开始,您可以使用其子类覆盖类常量。这是由于在PHP中实现继承的方式。 以下是如何覆盖先前声明的常量值的示例: 复制 class Moo { public const M = "moo"; } class Meow extends Moo { public const M = "meow"; } 现在,如果奶牛想要更严格地控制猫的行为(至少在常量方面),他们可以使用PHP 8.1的新final修饰符来实现。 一旦你声明了一个常量为 final,就意味着。 复制 class Moo { final public const M = "moo"; } class Meow extends Moo { public const M = "meow"; } // Fatal error: Meow::M cannot override final constant Moo::M 您可以在最后的类常量PHP RFC中阅读更多关于它的内容。 新的fsync()和fdatasync()函数 PHP 8.1添加了两个名为fsync()和fdatasync()新文件系统函数。对于那些习惯于Linux同名函数的人来说,它们似乎很熟悉。那是因为它们是相关的,只是为PHP实现的。 事实上,这一补充早该进行了。PHP是少数仍未实现fsync() 和 fdatasync() 的主要编程语言之一——也就是说,直到PHP 8.1。 fsync()函数类似于PHP现有的fflush()函数,但在一个方面有很大不同。而fflush()将应用程序的内部缓冲区刷新到操作系统,fsync()则更进一步并确保将内部缓冲区刷新到物理存储。这确保了完整且持久的写入,以便您即使在应用程序或系统崩溃后也可以检索数据。 这是一个如何使用它的示例。 复制 $doc = 'kinsta.txt'; $kin = fopen($doc, 'ki'); fwrite($kin, 'doc info'); fwrite($kin, "\r\n"); fwrite($kin, 'more info'); fsync($kin); fclose($kin); fsync()在末尾添加调用可确保保存在 PHP 或操作系统内部缓冲区中的任何数据都被写入存储。在此之前,所有其他代码执行都将被阻止。 它的相关函数是fdatasync()。使用它来同步数据,但不一定是元数据。对于元数据不是必需的数据,此函数调用会使写入过程更快一点。 但是,您应该注意PHP 8.1在Windows下尚不完全支持fdatasync()。它只是作为fsync()的别名。在POSIX上,fdatasync()已正确实施。 新的array_is_list()函数 PHP数组可以保存整数和字符串键。这意味着您可以将它们用于多种用途,包括列表、哈希表、字典、集合、堆栈、队列等等。您甚至可以在数组中包含数组,从而创建多维数组。 您可以有效地检查特定条目是否为数组,但检查它是否有任何缺失的数组偏移量、乱序键等就不是那么容易了。简而言之,您无法快速验证数组是否为列表。 所述array_is_list()函数检查是否一个数组的键是按顺序从0开始,并与没有间隙。如果满足所有条件,它将返回true。默认情况下,它还返回true空数组。 以下是在同时满足true和false条件的情况下使用它的几个示例: 复制 // true array_is_list() examples array_is_list([]); // true array_is_list([1, 2, 3]); // true array_is_list(['cats', 2, 3]); // true array_is_list(['cats', 'dogs']); // true array_is_list([0 => 'cats', 'dogs']); // true array_is_list([0 => 'cats', 1 => 'dogs']); // true // false array_is_list() examples array_is_list([1 => 'cats', 'dogs']); // as first key isn't 0 array_is_list([1 => 'cats', 0 => 'dogs']); // keys are out of order array_is_list([0 => 'cats', 'bark' => 'dogs']); // non-integer keys array_is_list([0 => 'cats', 2 => 'dogs']); // gap in between keys 带有乱序键的PHP数组列表是潜在的错误来源。在继续执行代码之前,使用此函数强制严格遵守列表要求是对PHP的一个很好的补充。 新的Sodium XChaCha20函数 Sodium是一个现代的、易于使用的加密库,用于加密、解密、密码散列、签名等。该PECL libsodium包增加了对钠的包装,使PHP开发人员可以使用它。 即使是Facebook、Discord、Malwarebytes和Valve等领先的科技公司也使用libsodium来通过快速安全的连接来保护他们的用户。 libsodium支持XChaCha20加密算法对数据进行加密和解密,特别是对流加密。同样,PECL libsodium扩展已经支持XChaCha20,但仅支持Poly1305消息验证代码。 许多PHP应用程序直接使用XChaCha20进行流加密。为了让事情变得更简单,从PHP 8.1开始,您将拥有三个新函数,无需身份验证即可使用XChaCha20加密或解密数据。这种模式称为“分离模式”。 新推出的XChaCha20函数是: sodium_crypto_stream_xchacha20_keygen: 返回一个安全的随机密钥,用于sodium_crypto_stream_xchacha20。 sodium_crypto_stream_xchacha20:将密钥和随机数扩展为伪随机字节的密钥流。 sodium_crypto_stream_xchacha20_xor:使用随机数和密钥(无身份验证)加密消息。 此外,在全局命名空间中定义了两个新的PHP常量: SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES(分配32) SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES(分配24) 不过请谨慎使用。由于没有身份验证,解密操作容易受到常见的密文攻击。 您可以在GitHub页面上阅读有关其用法和要求的更多信息。 新的IntlDatePatternGenerator类 PHP的底层ICU库支持创建本地化的日期和时间格式,但不能完全自定义。 例如,如果您想在PHP 8.0之前创建特定于语言环境的数据和时间格式,您可以使用预定义的IntlDateFormatter常量以6种方式完成: IntlDateFormatter::LONG:更长,例如November 10, 2017 or 11:22:33pm IntlDateFormatter::MEDIUM:短一点,比如November 10, 2017 IntlDateFormatter::SHORT:只是数字,比如10/11/17 or 11:22pm 其中每一个也有自己的RELATIVE_变体,将日期格式设置在当前日期之前或之后的有限范围内。在 PHP 中,值是yesterday, today和tomorrow。 假设您想使用年份的长版本和月份的短版本,例如10/11/2017。但在PHP 8.0,你不能这样做。 在PHP 8.1+中,您可以使用新的IntlDatePatternGenerator类指定日期、月份和时间使用的格式。您可以将这些组件的确切顺序留给格式化程序。 您应该注意到,虽然这个类中只有Date一词,但它与ICU的DateTimePatternGenerator一致。这意味着您还可以使用它来创建灵活的时间格式。为了简化命名,PHP团队选择使用较短的IntlDatePatternGenerator术语。 这是直接来自其RFC的示例: 复制 $skeleton = "YYYYMMdd"; $today = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-04-24'); $dtpg = new \IntlDatePatternGenerator("de_DE"); $pattern = $dtpg->getBestPattern($skeleton); echo "de: ", \IntlDateFormatter::formatObject($today, $pattern, "de_DE"), "\n"; $dtpg = new \IntlDatePatternGenerator("en_US"); $pattern = $dtpg->getBestPattern($skeleton), "\n"; echo "en: ", \IntlDateFormatter::formatObject($today, $pattern, "en_US"), "\n"; /* de: 24.04.2021 en: 04/24/2021 */ 在上面的代码中,skeleton变量定义了要使用的特定日期或时间格式。但是,格式化程序处理最终结果的顺序。 支持AVIF图像格式 AVIF或AV1图像文件格式,是一种基于AV1视频编码格式的相对较新的免版税图像格式。除了提供更高的压缩率(因此文件更小)之外,它还支持多种特性,例如透明度、HDR等。 AVIF格式最近才标准化(2021年6月8日)。这为Chrome 85+和Firefox 86+等浏览器增加了对AVIF图像的支持铺平了道路。 PHP 8.1的图像处理和GD扩展增加了对AVIF图像的支持。 但是,要包含此特性,您需要编译具有AVIF支持的GD扩展。您可以通过运行以下命令来执行此操作。 对于Debian/Ubuntu: 复制 apt install libavif-dev 对于Fedora/RHEL: 复制 dnf install libavif-devel 这将安装所有最新的依赖项。接下来,您可以通过--with-avif使用./configure脚本运行标志来编译AVIF支持。 复制 ./buildconf --force ./configure --enable-gd --with-avif 如果您要从头开始一个新环境,您还可以在此处启用其他PHP扩展。 安装后,您可以通过在PHP终端中运行以下命令来测试是否启用了AVIF支持: 复制 php -i | grep AVIF 如果您已正确安装AVIF,您将看到以下结果: 复制 AVIF Support => enabled 您还可以使用gd_info()调用来检索GD功能列表,包括是否启用了AVIF支持功能。 这个更新的PHP 8.1 GD扩展还添加了两个用于处理AVIF图像的新函数:imagecreatefromavif和imageavif. 它们的工作方式与JPEG和PNG对应物类似。 imagecreatefromavif函数从给定的AVIF图像返回一个GdImage实例。然后,您可以使用此实例来编辑或转换图像。 另一个imageavif函数输出AVIF图像文件。例如,您可以使用它将JPEG转换为AVIF: 复制 $image = imagecreatefromjpeg('image.jpeg'); imageavif($image, 'image.avif'); 您可以在其GitHub页面上阅读有关此新特征的更多信息。 新的目录上传$_FILES: full_path键 PHP维护了大量预定义变量来跟踪各种事物。其中之一是$_FILES 变量保存通过HTTP POST方法上传的项目的关联数组。 大多数现代浏览器都支持使用HTML文件上传字段上传整个目录。甚至PHP<8.1也支持此功能,但有一个很大的警告。您无法上传具有确切目录结构或相对路径的文件夹,因为PHP没有将此信息传递给$_FILES数组。 这与另外一个名为新的关键的变化在PHP 8.1full_path的$_FILES阵列。使用这些新数据,您可以在服务器上存储相对路径或复制确切的目录结构。 您可以通过$FILES使用var_dump($_FILES);命令输出数组来测试此信息。 但是,如果您正在使用此功能,请谨慎操作。确保您防范标准文件上传攻击。 对字符串键控数组的数组解包支持 PHP 7.4添加了对使用数组展开运算符 ( … )进行数组解包的支持。它可以作为使用array_merge()函数的更快替代方法。但是,此特性仅限于数字键数组,因为在合并具有重复键的数组时,解包字符串键数组会导致冲突。 但是,PHP 8添加了对命名参数的支持,消除了这个限制。因此,数组解包现在也支持使用相同语法的字符串键数组: 复制 $array = [...$array1, ...$array2]; 这个RFC示例说明了如何在PHP 8.1中处理合并具有重复字符串键的数组: 复制 $array1 = ["a" => 1]; $array2 = ["a" => 2]; $array = ["a" => 0, ...$array1, ...$array2]; var_dump($array); // ["a" => 2] 在这里,字符串键“a”在通过数组解包合并之前出现了三次。但只有它属于$array2的最后一个值获胜。 显式八进制数字表示法 PHP 支持各种数字系统,包括十进制 (base-10)、二进制 (base-2)、八进制 (base-8) 和十六进制 (base-16)。十进制数字系统是默认值。 如果你想使用任何其他数字系统,那么你必须在每个数字前加上一个标准前缀: 十六进制: 0x前缀。(例如 17 = 0x11) 二进制: 0b前缀。(例如 3 = 0b11) 八进制: 0前缀。(例如 9 = 011) 您可以看到八进制数字系统的前缀与其他系统的前缀有何不同。为了标准化这个问题,许多编程语言增加了对显式八进制数字符号的支持:0o或0O。 从PHP 8.1开始,您可以在八进制数字系统中将上述示例(即以10为基数的数字9)编写为0o11或0O11。 复制 0o16 === 14; // true 0o123 === 83; // true 0O16 === 14; // true 0O123 === 83; // true 016 === 0o16; // true 016 === 0O16; // true 此外,这个新特性也适用于PHP 7.4中引入的下划线数字文字分隔符。 在其RFC中阅读有关此新PHP 8.1特征的更多信息。 MurmurHash3和xxHash哈希算法支持 PHP 8.1添加了对MurmurHash3和xxHash散列算法的支持。它们不是为加密用途而设计的,但它们仍然提供令人印象深刻的输出随机性、分散性和唯一性。 这些新的散列算法比大多数PHP现有的散列算法都快。事实上,其中一些散列算法的变体比RAM吞吐量更快。 由于PHP 8.1还增加了对声明特定于算法的$options参数的支持,您可以对这些新算法执行相同的操作。这个新参数的默认值为[]。因此,它不会影响我们现有的任何哈希函数。 您可以在他们的GitHub页面上阅读有关这些PHP 8.1新功能的更多信息:MurmurHash3、xxHash、Algorithm-specific $options. DNS-over-HTTPS (DoH) 支持 DNS-over-HTTPS (DoH) 是一种通过HTTPS协议进行DNS解析的协议。DoH使用HTTPS加密客户端和DNS解析器之间的数据,通过防止中间人攻击来提高用户隐私和安全性。 从PHP 8.1开始,您可以使用Curl扩展来指定DoH服务器。它需要使用libcurl 7.62+版本编译PHP。对于大多数流行的操作系统(包括Linux发行版)来说,这不是问题,因为它们通常包含Curl 7.68+。 您可以通过指定CURLOPT_DOH_URL选项来配置DoH服务器URL 。 复制 $doh = curl_init('https://www.wbolt.com'); curl_setopt($doh, CURLOPT_DOH_URL, 'https://dns.google/dns-query'); curl_exec($doh); 在上面的示例中,我们使用了Google的公共DNS服务器。另外,请注意https://在所有使用的URL中的使用。确保完美地配置它,因为在Curl中没有可以回退的默认DNS服务器。 您还可以从Curl文档中包含的公共DoH服务器列表中进行选择。 此外,Curl文档的CURLOPT_DOH_URL 参考解释了如何彻底使用其各种参数。 使用CURLStringFile从字符串上载文件 PHP Curl扩展支持带有文件上传的HTTP(S)请求。它使用CURLFile类来实现这一点,该类接受URI或文件路径、mime类型和最终文件名。 但是,使用CURLFile类,您只能接受文件路径或URI,而不能接受文件本身的内容。如果您已经将文件上传到内存中(例如处理过的图像、XML文档、PDF),您必须使用data://Base64编码的URI。 但是libcurl已经支持一种更简单的方式来接受文件的内容。新的CURLStringFile类增加了对此的支持。 您可以阅读其GitHub页面以了解有关如何在PHP 8.1中实现的更多信息。 新的MYSQLI_REFRESH_REPLICA常数 PHP 8.1的mysqli扩展添加了一个名为MYSQLI_REFRESH_REPLICA. 它相当于现有的MYSQLI_REFRESH_SLAVE常数。 这个变化在MySQL 8.0.23中受到欢迎,以解决技术词汇中的种族不敏感问题(最常见的例子包括“奴隶”和“主人”)。 您应该注意到旧的常量没有被删除或弃用。开发人员和应用程序可以继续使用它。对于希望抛弃此类术语的开发人员和公司而言,此新常量只是一种选择。 使用继承缓存提高性能 继承缓存(Inheritance Cache )是opcache的新增功能,可消除PHP类继承开销。 PHP类由opcache单独编译和缓存。但是,它们已经在运行时针对每个请求进行了链接。这个过程可能涉及几个兼容性检查和从父类和特征借用方法/属性/常量。 因此,即使每个请求的结果都相同,这仍需要相当长的时间来执行。 继承缓存链接所有唯一的依赖类(父类、接口、特征、属性类型、方法)并将结果存储在opcache共享内存中。由于这种情况现在只发生一次,因此继承需要较少的指令。 此外,它消除了对不可变类的限制,例如未解析的常量、类型化属性和协变类型检查。因此,存储在opcache中的所有类都是不可变的,进一步减少了所需的指令数量。 总而言之,它有望带来显着的性能优势。该补丁的作者Dimitry Stogov发现它在基础Symfony “Hello, World!” 上有8%的改进。程序。我们迫不及待地想在我们的以下PHP基准测试中测试它。 First-Class可调用语法 PHP 8.1添加了First-Class可调用语法来取代使用字符串和数组的现有编码。除了创建更干净的Closure 之外,静态分析工具也可以访问这种新语法并尊重声明的范围。 以下是一些取自RFC的示例: 复制 $fn = Closure::fromCallable('strlen'); $fn = strlen(...); $fn = Closure::fromCallable([$this, 'method']); $fn = $this->method(...) $fn = Closure::fromCallable([Foo::class, 'method']); $fn = Foo::method(...); 这里,所有的表达式对都是等价的。三点 ( … ) 语法类似于参数解包语法 ( ...$args)。除了这里,参数尚未填写。 PHP 8.1中的变化 PHP 8.1 还包括对其现有语法和功能的更改。让我们来讨论它们: PHP Interactive Shell需要readline扩展 MySQLi默认错误模式设置为异常 CSV写入函数的可定制行尾 新version_compare运算符限制 HTML编码和解码函数现在使用ENT_QUOTES | ENT_SUBSTITUTE 关于非法紧凑函数调用的警告 新的从资源到类对象的迁移 PHP Interactive Shell需要readline扩展 PHP的readline扩展支持交互式shell功能,例如导航、自动完成、编辑等。虽然它与PHP捆绑在一起,但默认情况下并未启用。 您可以使用PHP CLI的-a命令行选项访问PHP交互式shell: 复制 php -a Interactive shell php > php > echo "Hello"; Hello php > function test() { php { echo "Hello"; php { } php > test(); Hello 在PHP 8.1之前,即使没有启用readline扩展,您也可以使用PHP CLI打开交互式shell 。正如预期的那样,shell的交互功能不起作用,使该-a选项变得毫无意义。 在PHP 8.1 CLI中,如果您没有启用readline扩展,交互式shell会退出并显示错误消息。 复制 php -a Interactive shell (-a) requires the readline extension. MySQLi默认错误模式设置为异常 在PHP 8.1之前,MySQLi默认为静默错误。这种行为通常会导致代码不遵循严格的错误/异常处理。开发人员必须实现自己的显式错误处理功能。 PHP 8.1通过将MySQLi的默认错误报告模式设置为抛出异常来更改此行为。 复制 Fatal error: Uncaught mysqli_sql_exception: Connection refused in ...:... 由于这是一个重大更改,对于PHP<8.1版本,您应该mysqli_report在建立第一个MySQLi连接之前使用该函数显式设置错误处理模式。或者,您可以通过实例化一个mysqli_driver实例来选择错误报告值来执行相同的操作。 RFC遵循PHP 8.0中引入的类似更改。 CSV写入函数的可定制行尾 在PHP 8.1之前,PHP的内置CSV写入函数fputcsv和SplFileObject::fputcsv被硬编码为\n 在每行末尾添加(或换行符)。 PHP8.1为这些函数添加了对名为eol的新参数的支持。您可以使用它来传递可配置的行尾字符。默认情况下,它仍然使用\n 字符。因此,您可以继续在现有代码中使用它。 标准字符转义规则适用于使用行尾字符。如果您想使用\r、\n或\r\n作为EOL字符,您必须将它们括在双引号中。 这是跟踪此新更改的GitHub页面。 新的 version_compare 运算符限制 PHP的version_compare()函数比较两个版本号字符串。此函数接受一个可选的第三个参数,operator用于测试特定关系。 尽管文档中没有明确说明,但在PHP 8.1之前,您可以将此参数设置为部分值(例如g, l, n)而不会出现错误。 PHP 8.1对version_compare()函数的operator参数添加了更严格的限制来克服这种情况。您现在可以使用的唯一运算符是: ==、=和eq !=、<>和ne >和gt >=和ge <和lt <=和le 没有更多的部分运算符值。 HTML编码和解码函数改用 ENT_QUOTES | ENT_SUBSTITUTE HTML实体是字符的文本表示,否则会被解释为HTML。想想诸如<和>用于定义HTML 标签的字符(例如<a>、<h3>、<script>)。 HTML实体<是& lt;(小于符号)和>是& gt;(大于符号)。 注意:删除“&”和“amp”之间的空格。 您可以在HTML文档中安全地使用这些HTML实体,而无需触发浏览器的渲染引擎。 例如,& lt;script& gt;将在浏览器中显示为<script>,而不是被解释为HTML标记。 之前PHP 8.1,则用htmlspecialchars()和 htmlentities() 函数转换如 “, <, >和& 符号为各自的HTML实体。但默认情况下,他们没有将单引号字符 (') 转换为其HTML实体。此外,如果文本中存在格式错误的 UTF-8,它们将返回一个空字符串。 在PHP 8.1中,这些HTML编码和解码函数(及其相关函数)也会默认将单引号字符转换为它们的HTML实体。 如果给定的文本包含无效字符,函数将用Unicode替换字符 (�) 替换它们,而不是返回空字符串。PHP 8.1通过默认将这些函数的签名更改为ENT_QUOTES | ENT_SUBSTITUTE而不是ENT_COMPAT来实现这一点。 大多数框架已经ENT_QUOTES用作默认标志值。因此,由于此更改,您不会看到太大差异。然而,新ENT_SUBSTITUTE标志并没有被广泛使用。PHP 8.1将导致无效的UTF-8字符被替换为 � 字符而不是返回空字符串。 关于非法紧凑函数调用的警告 PHP 的compact()函数超级好用。您可以使用它来创建一个数组,其中包含使用名称和值的变量。 例如,考虑以下代码: 复制 $animal = 'Cat'; $sound = 'Meow'; $region = 'Istanbul'; compact('animal', 'sound', 'region'); // ['animal' => "Cat", 'sound' => "Meow", 'region' => "Istanbul"] 紧凑型函数的文档指出,这将只接受字符串参数或字符串值数组值。但是,在PHP 7.3之前,任何未设置的字符串都将被悄悄跳过。 PHP7.3修改了compact()函数,以便在使用未定义变量时发出通知。PHP 8.1更进一步,并发出警告。 您可以阅读其GitHub 页面以了解此更改是如何发生的。 新的从资源到类对象迁移 PHP的长期目标之一是从资源转向标准类对象。 由于历史原因,资源对象在PHP应用程序中被广泛使用。因此,资源向类对象的迁移需要尽可能减少破坏性。PHP 8.1迁移了五个这样的资源: 将file_info资源迁移到finfo对象 PHP的finfo 类为函数提供了一个面向对象的接口fileinfo。但是,使用finfo函数返回resource具有file_info类型的对象而不是finfo类本身的实例。 PHP 8.1修复了这个异常。 迁移到IMAP\Connection类对象的IMAP资源 根据资源到对象的迁移目标,当PHP最终修改类的实现细节时,新的IMAP\Connection类将潜在的破坏性更改降至最低。 这个新类也被声明final,所以你不被允许extend。 在其GitHub页面上阅读有关其实现的更多信息。 FTP连接资源现在为FTP\Connection类对象 在PHP<8.1中,如果您使用或函数ftp_connect()或者ftp_ssl_connect()创建FTP连接,您将返回一个ftp类型的资源对象。 PHP 8.1添加了新的FTP\Connection类来纠正这个问题。和IMAP\Connection类一样,它也被声明final为防止它被扩展。 在其GitHub页面上阅读有关其实现的更多信息。 字体标识符迁移到GdFont类对象 PHP的GD扩展提供了imageloadfont() 函数来加载用户定义的位图并返回其字体标识符资源 ID(一个整数)。 在PHP 8.1中,此函数将改为返回GdFont类实例。此外,为了使迁移轻松自如,以前从imageloadfont()接受资源ID的所有函数现在都将采用新的GdFont类对象。 在其GitHub页面上阅读有关此迁移的更多信息。 LDAP资源迁移到对象 LDAP或轻量级目录访问协议,用于访问“目录服务器”。就像硬盘目录结构一样,它是一个独特的数据库,以树状结构保存数据。 PHP包含一个LDAP扩展,它接受或返回PHP 8.1之前的资源对象。但是,它们现在都已无缝迁移到新的类实例。已经过渡的资源类型有: ldap link资源到\LDAP\Connection类对象 ldap result资源到\LDAP\Result类对象 ldap result entry资源到\LDAP\ResultEntry类对象 浏览其GitHub页面以更好地了解此迁移。 Pspell资源现在为类对象 PHP的Pspell扩展允许您检查拼写和单词建议。 PHP<8.1使用pspell和pspell config带有整数标识符的资源对象类型。这两个资源对象现在替换为PSpell\Dictionary和PSpell\Config类对象。 与之前的迁移一样,之前接受或返回资源对象标识符的所有Pspell函数都将采用新的类对象实例。 有关更多信息,请参阅其GitHub页面。 PHP 8.1中的弃用 PHP 8.1弃用了许多以前的功能。以下列表简要概述了PHP 8.1弃用的功能: 不能将null传递给不可为Null的内部函数参数 受限制的$GLOBALS使用 内部函数的返回类型声明 不推荐使用可序列化接口 不兼容的float到int转换已弃用 mysqli::get_client_info方法和mysqli_get_client_info($param) 已弃用 不推荐使用所有mhash*() 函数(散列扩展) filter.default和filter.default_options INI设置已弃用 在false上弃用autovivification 不推荐使用mysqli_driver->driver_version属性 不能将null 传递给不可为Null的内部函数参数 从PHP 8.0开始,它的内部函数null即使对于不可为null的参数也默默地接受值。这不适用于用户定义的函数——它们只接受null可为空的参数。 例如,考虑这种用法: 复制 var_dump(str_contains("foobar", null)); // bool(true) 在这里,null值被静默转换为空字符串。因此,结果返回true。 该RFC旨在通过在PHP 8.1中抛出弃用警告来同步内部函数的行为。 复制 var_dump(str_contains("foobar", null)); // Deprecated: Passing null to argument of type string is deprecated 在下一个主要的 PHP 版本(即 PHP >=9.0)中,弃用将成为 TypeError,使内部函数的行为与用户定义的函数保持一致。 限制$GLOBALS使用 PHP的$GLOBALS变量提供对其内部符号表的直接引用。支持此功能很复杂,并且会影响阵列操作性能。另外,它很少被使用。 根据RFC,$GLOBALS不再允许间接修改。此更改向后不兼容。 这种变化的影响相对较低: 在前2k个composer包中,我发现了23个使用 $GLOBALS而不直接取消引用它的案例。根据粗略的检查,只有两种情况没有以只读方式使用$GLOBALS。 但是,只读用法$GLOBALS继续照常工作。不再支持的是$GLOBALS整体写入。因此,您可能会遇到轻微的性能提升,尤其是在使用普通PHP数组时。 内部函数的返回类型声明 PHP 8.0允许开发人员为大多数内部函数和方法声明参数和返回类型。这要归功于各种RFC,例如内部函数的一致类型错误、联合类型2.0和混合类型v2。 但是,在很多情况下可能会丢失类型信息。其中一些包括具有资源型,out pass-by-ref 参数,非final方法返回类型,函数或不按一般规则解析参数的方法。您可以在其RFC中阅读确切的详细信息。 此RFC仅解决非最终方法的返回类型的问题。然而,PHP团队并没有立即完全淘汰它,而是提供了一个渐进的迁移路径,以使用相关的方法返回类型更新您的代码库。 非最终的内部方法返回类型(如果可能)在PHP 8.1中暂时声明,它们将在PHP 9.0中强制执行。这意味着在PHP 8.x版本中,当内部方法以返回类型不兼容的方式被覆盖时,在继承检查期间会引发“弃用”通知,而PHP 9.0会使这些成为致命错误。 如果您在更新到PHP 8.1后看到此弃用通知,请确保更新您的方法的返回类型。 不推荐使用可序列化接口 PHP 7.4通过两个新的魔术方法引入了自定义对象序列化机制:__serialize()和__unserialize(). 这些新方法旨在最终替换损坏的Serializable接口。 该RFC提议通过制定最终删除Serializable的计划来最终确定该决定。 在PHP 8.1中,如果你在没有实现和方法的情况下实现了Serializable接口,PHP将抛出“Deprecated”警告。 在PHP8.1中,如果在没有实现__serialize()和__unserialize()方法的情况下实现Serializable接口,PHP将抛出“Deprecated”警告。 复制 Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in ... on line ... 如果你支持PHP <7.4和PHP >=7.4,你应该实现Serializable接口和新的魔法方法。在PHP >=7.4版本上,魔术方法将优先。 不推荐使用不兼容的float 到int 转换 PHP是一种动态类型语言。因此,在很多情况下自然会发生类型强制。大多数这些强制是无害的,而且超级方便。 但是,当浮点数转换为整数时,通常会涉及数据丢失。例如,当浮点数3.14转换为整数3时,它会丢失其小数值。 当浮点数超出平台整数范围或浮点数字符串转换为整数时,也会发生同样的情况。 PHP 8.1纠正了这种行为,并使其动态类型强制更符合大多数现代编程语言。目标是使这种强制可预测和直观。 在PHP 8.1中,当不兼容的float被隐式强制转换为int时,您将看到弃用通知。但是什么构成了整数兼容的浮点数?RFC对此做出了回答: 如果具有以下特征,则称浮点数与整数兼容: 是一个数字(即不是 NaN 或无穷大) 在PHP整数范围内(取决于平台) 没有小数部分 此弃用通知将在下一个主要PHP版本(即PHP 9.0)中升级为TypeError。 mysqli::get_client_info和mysqli_get_client_info($param)方法已过时 MySQL客户端API定义了两个常量:client_info(字符串)和client_version(整数)。MySQL Native Driver (MySQLnd) 是官方PHP源代码的一部分,并将这些常量与PHP版本挂钩。在libmysql中,它们代表编译时的客户端库版本。 在PHP8.1之前,mysqli以4种方式公开这些常量:mysqli_driver属性、mysqli 属性、mysqli_get_client_info()函数和mysqli::get_client_info方法。但是,对于client_version没有方法。 MySQLnd 以两种方式向PHP公开这些常量:常量和函数调用。为了统一使用这两个选项的mysqli访问方法,PHP 8.1弃用了其他两个选项: get_client_infomysqli类中的方法。相反,您可以只使用该mysqli_get_client_info()函数。 mysqli_get_client_info()带参数的函数。不带任何参数调用函数以避免弃用通知。 在其GitHub 页面上阅读有关此弃用的更多信息。 不推荐使用所有mhash*()函数(散列扩展) PHP5.3将mhash*()函数集成到ext/hash中,作为ext/mhash的兼容层。后来,PHP7.0删除了ext/mhash。 与hash_*()函数不同,mhash*()函数并不总是可用。您必须在配置PHP时单独启用它们。 在PHP 7.4中,散列扩展与PHP捆绑在一起,使其成为PHP的默认扩展。但是,--enable-mhash出于兼容性原因,它仍然支持启用该选项。 PHP团队决定在PHP 8.1中弃用mhash*()函数,并在PHP 9.0中完全删除它们。不推荐使用的函数是mhash(),mhash_keygen_s2k(),mhash_count(),mhash_get_block_size()和mhash_get_hash_name()。您可以使用标准ext/hash功能代替它们。 filter.default和filter.default_optionsINI设置已过时 PHP的filter.defaultINI设置允许您将过滤器适用于所有的PHP超全局-即GPCR的数据($_GET,$_POST,$_COOKIE,$_REQUEST,和$_SERVER)。 例如,您可以设置filter.default=magic_quotes或filter.default=add_slashes(基于PHP版本)来复活PHP有争议且不安全的魔术引号功能(在PHP 5.4中删除)。 filter.default的INI设置提供了额外的功能,允许使用更多的过滤器,使情况变得更糟。例如,它的另一个选项-filter.default=special_chars -只为HTML启用魔法引号。人们对这些设置的了解要少得多。 如果filter.default 设置为除unsafe_raw(默认值)以外的任何值,PHP8.1将抛出一个弃用警告。您不会看到ilter.default_options的单独弃用通知,但PHP9.0将删除这两个INI设置。 作为替代方案,您可以开始使用filter_var()函数。它使用指定的过滤器过滤变量。 弃用autovivification的false PHP允许自动激活(从假值自动创建数组)。如果变量未定义,此功能非常有用。 尽管如此,当值为false或null时自动创建数组并不理想。 此RFC不允许从错误值自动激活。但是,请注意,仍然允许来自未定义变量和null的自动激活。 在PHP 8.1中,附加到false类型的变量将发出弃用通知: 复制 Deprecated: Automatic conversion of false to array is deprecated in PHP 9.0同样会抛出致命错误,这与其他标量类型相同。 mysqli_driver->driver_version属性已弃用 MySQLi 扩展的mysqli_driver->driver_version属性已经13年没有更新了。尽管此后对驱动程序进行了许多更改,但它仍然返回旧的驱动程序版本值,使该属性变得毫无意义。 在PHP 8.1中,mysqli_driver->driver_version属性已弃用。 其他小改动 PHP 8.1中有更多的弃用。将它们全部列出在这里将是一项令人筋疲力尽的工作。我们建议您直接查看RFC以了解这些较小的弃用情况。 PHP的GitHub页面还包括一个PHP 8.1升级说明指南。它列出了在升级到PHP 8.1之前您应该考虑的所有重大更改。 小结 PHP 8.1离我们不远了。并且它已经承诺将其前身提升一倍,这是不小的壮举。 我们认为最令人兴奋的PHP 8.1特性是枚举、纤维、纯交集类型及其许多性能改进。此外,我们迫不及待地要让PHP 8.1步入正轨,并对各种PHP框架和CMS进行基准测试。
===========php8===========
===================================Php8================================================ 1.联合类型 PHP7 class Number { /** @var int|float */ private $number; /** * @param float|int $number */ public function __construct($number) { $this->number = $number; } } new Number('NaN'); // Ok PHP8 class Number { public function __construct( private int|float $number ) {} } new Number('NaN'); // TypeError 2.mixed类型 mixed本身是以下类型之一: array bool callable int float null object resource string 注意,mixed也可以用作参数或属性类型,而不仅仅是返回类型。 另外由于mixed已经包含null,因此不允许将其设置为nullable。以下内容将触发错误 3.JIT作为PHP底层编译引擎,对于PHP8的性能贡献是非常之大,不过对于常规WEB应用来说,优势不明显,但仍然是非常的高大上特性,是PHP8的扛鼎之作 4.最实用的特性:构造器属性提升、Nullsafe运算符、str_contains()、 str_starts_with()、 str_ends_with() 5.构造器属性提升 代替如下代码: class Money { public Currency $currency; public int $amount; public function __construct( Currency $currency, int $amount, ) { $this->currency = $currency; $this->amount = $amount; } } 你可以这样做: class Money { public function __construct( public Currency $currency, public int $amount, ) {} } 6.nullsafe运算符 现在可以用新的 nullsafe 运算符链式调用,而不需要条件检查 null。 如果链条中的一个元素失败了,整个链条会中止并认定为 Null。 $country =null; if ($session !== null) { $user = $session->user; if ($user !== null) { $address = $user->getAddress(); if ($address !== null) { $country = $address->country; } } } 简化为一行代码 $country = $session?->user?->getAddress()?->country; 7.确实是有点酷 str_contains()、str_starts_with()和str_ends_with()函数 有些人可能会说它早就该有了,但我们终于不必再依赖strpos() 来知道字符串是否包含另一个字符串了。 代替如下: if (strpos('string with lots of words', 'words') !== false) { /* … */ } 你可以这样做 if (str_contains('string with lots of words', 'words')) { /* … */ } 感觉大多数场景应该是不需要使用strpos了吧,外两个早就应该有了,str_starts_with()和str_ends_with()这两个函数现在能省事不少。 str_starts_with('haystack', 'hay'); // true str_ends_with('haystack', 'stack'); // true 8.最具潜力的特性:注解、Match表达式、WeakMap 现在可以用原生的PHP语法来使用结构化的元数据,而不需要再依赖PHPDoc解析,性能也随之提升。之前定义注解路由可能需要使用: class PostsController { /** * @Route("/api/posts/{id}", methods={"GET"}) */ public function get($id) { /* ... */ } } 现在你可以直接用PHP的注解语法来定义,并通过反射直接获取 class PostsController { #[Route("/api/posts/{id}", methods: ["GET"])] public function get($id) { /* ... */ } } 9.Match表达式 你可以称它为switch表达式的大哥:match可以返回值,不需要break语句,可以组合条件,使用严格的类型比较,并且不执行任何类型的强制。 如下所示: $result = match($input) { 0 => "hello", '1', '2', '3' => "world", }; 10.WeakMap WeakMap保留对对象的引用,这些引用不会阻止这些对象被垃圾回收。 特别是在 ORM 的情况下,它可以管理请求中的数百个,如果不是数千个实体;weak maps可以提供更好、更资源友好的处理这些对象的方法。 下面是weak maps的示例: class Foo { private WeakMap $cache; public function getSomethingWithCaching(object $obj): object { return $this->cache[$obj] ??= $this->computeSomethingExpensive($obj); } } 11其它特性 php7 0 == 'foobar' // 返回true php8 0 == 'foobar' // 返回false 可以在对象上使用::class $foo = new Foo(); var_dump($foo::class); 现在可以对对象使用::class,它的工作方式与 get_class() 相同。 12.traits 中的抽象方法改进 Traits 可以指定抽象方法,这些方法必须由使用它们的类实现。在PHP8,必须保持一致的方法定义,包括参数类型和返回类型。
==========php7.4==========
====================================7.4========================================= 1、属性值类型声明 <?php class User { public int $id; public string $name; } 2、箭头函数 <?php $factor = 10; $nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]); // $nums = array(10, 20, 30, 40); 3、空值连写赋值运算符 <?php $array['key'] ??= computeDefault(); // is roughly equivalent to if (!isset($array['key'])) { $array['key'] = computeDefault(); } 4、数组内展开 <?php $parts = ['apple', 'pear']; $fruits = ['banana', 'orange', ...$parts, 'watermelon']; // ['banana', 'orange', 'apple', 'pear', 'watermelon']; 5、数值型字面量分隔符 <?php 6.674_083e-11; // float 299_792_458; // decimal 0xCAFE_F00D; // hexadecimal 0b0101_1111; // binary 6、弱引用 引用对象使其不被销毁 7、__toString()方法允许跑出异常
=======php7.2==========
====================================php7.2====================================== 1、Nullable类型 参数以及返回值的类型通过在类型前加上一个问号使之允许为空 <?php function testReturn(): ?string { return 'elePHPant'; } var_dump(testReturn()); function testReturn(): ?string { return null; } var_dump(testReturn()); function test(?string $name) { var_dump($name); } test('elePHPant'); test(null); test(); 2、Void 函数 方法要么干脆省去 return 语句,要么使用一个空的 return 语句。 对于 void 函数来说,NULL 不是一个合法的返回值。 <?php function swap(&$left, &$right) : void { if ($left === $right) { return; } $tmp = $left; $left = $right; $right = $tmp; } $a = 1; $b = 2; var_dump(swap($a, $b), $a, $b); 3、对称性数组解构 短数组语法([])现在作为list()语法的一个备选项,可以用于将数组的值赋给一些变量(包括在foreach中) <?php $data = [ [1, 'Tom'], [2, 'Fred'], ]; // list() style list($id1, $name1) = $data[0]; // [] style [$id1, $name1] = $data[0]; // list() style foreach ($data as list($id, $name)) { // logic here with $id and $name } // [] style foreach ($data as [$id, $name]) { // logic here with $id and $name } 4、类常量可见性 <?php class ConstDemo { const PUBLIC_CONST_A = 1; public const PUBLIC_CONST_B = 2; protected const PROTECTED_CONST = 3; private const PRIVATE_CONST = 4; } 5、iterable 伪类 <?php function iterator(iterable $iter) { foreach ($iter as $val) { // } } 6、多异常捕获处理 <?php try { // some code } catch (FirstException | SecondException $e) { // handle first and second exceptions } 7、list()现在支持键名 这意味着它可以将任意类型的数组 都赋值给一些变量 <?php $data = [ ["id" => 1, "name" => 'Tom'], ["id" => 2, "name" => 'Fred'], ]; // list() style list("id" => $id1, "name" => $name1) = $data[0]; // [] style ["id" => $id1, "name" => $name1] = $data[0]; // list() style foreach ($data as list("id" => $id, "name" => $name)) { // logic here with $id and $name } // [] style foreach ($data as ["id" => $id, "name" => $name]) { // logic here with $id and $name } 8、支持为负的字符串偏移量 一个负数的偏移量会被理解为一个从字符串结尾开始的偏移量。 <?php var_dump("abcdef"[-2]); var_dump(strpos("aabbcc", "b", -3)); 7.2 1、新的object类型 这种新的类型 object, 引进了可用于逆变(contravariant)参数输入和协变(covariant)返回任何对象类型。 <?php function test(object $obj) : object { return new SplQueue(); } test(new StdClass()); 2、通过名称加载扩展 使用 dl() 函数进行启用 3、允许重写抽象方法(Abstract method) <?php abstract class A { abstract function test(string $s); } abstract class B extends A { // overridden - still maintaining contravariance for parameters and covariance for return abstract function test($s) : int; } 4、扩展了参数类型 重写方法和接口实现的参数类型现在可以省略了。不过这仍然是符合LSP,因为现在这种参数类型是逆变的。 <?php interface A { public function Test(array $input); } class B implements A { public function Test($input){} // type omitted for $input } 5、允许分组命名空间的尾部逗号 <?php use Foo\Bar\{ Foo, Bar, Baz, }; 6、更灵活的Heredoc 与 Nowdoc 语法 7、数组的解构支持引用赋值 [&$a, [$b, &$c]] = $d 8、Instanceof 运算符支持字面量 判断结果总是 FALSE 9、允许函数和方法被调用时参数最后的空逗号收尾 10、多字节字符串的相关函数 mb_convert_case(): mb_strtolower()) mb_strtoupper()) <?php mb_ereg('(?<word>\w+)', '国', $matches); // => [0 => "国", 1 => "国", "word" => "国"]; <?php mb_ereg_replace('\s*(?<word>\w+)\s*', "_\k<word>_\k'word'_", ' foo '); // => "_foo_foo_"
========php7.0==========
=========================================Php7============================================== 参数类型声明 标量类型声明 有两种模式: 强制 (默认) 和 严格模式。 现在可以使用下列类型参数(无论用强制模式还是严格模式): 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。 它们扩充了PHP5中引入的其他类型:类名,接口,数组和 回调类型。 <?php // Coercive mod function sumOfInts(int ...$ints) { return array_sum($ints); } var_dump(sumOfInts(2, '3', 4.1)); 2、返回值类型声明 返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。 <?php function arraysSum(array ...$arrays): array { return array_map(function(array $array): int { return array_sum($array); }, $arrays); } print_r(arraysSum([1,2,3], [4,5,6], [7,8,9])); 3、null合并运算符 如果变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。 <?php // Fetches the value of $_GET['user'] and returns 'nobody' // if it does not exist. $username = $_GET['user'] ?? 'nobody'; // This is equivalent to: $username = isset($_GET['user']) ? $_GET['user'] : 'nobody'; // Coalesces can be chained: this will return the first // defined value out of $_GET['user'], $_POST['user'], and // 'nobody'. $username = $_GET['user'] ?? $_POST['user'] ?? 'nobody'; ?> 4、太空船操作符(组合比较符) 用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1 <?php // 整数 echo 1 <=> 1; // 0 echo 1 <=> 2; // -1 echo 2 <=> 1; // 1 // 浮点数 echo 1.5 <=> 1.5; // 0 echo 1.5 <=> 2.5; // -1 echo 2.5 <=> 1.5; // 1 // 字符串 echo "a" <=> "a"; // 0 echo "a" <=> "b"; // -1 echo "b" <=> "a"; // 1 5、通过 define() 定义常量数组 在 PHP5.6 中仅能通过 const 定义。 <?php define('ANIMALS', [ 'dog' 'cat', 'bird' ]); echo ANIMALS[1]; // 输出 "cat" 6、匿名类 <?php interface Logger { public function log(string $msg); } class Application { private $logger; public function getLogger(): Logger { return $this->logger; } public function setLogger(Logger $logger) { $this->logger = $logger } } $app = new Application; $app->setLogger(new class implements Logger { public function log(string $msg) { echo $msg; } }); var_dump($app->getLogger()); 7、Unicode codepoint 转译语法 接受一个以16进制形式的 Unicode codepoint,并打印出一个双引号或heredoc包围的 UTF-8 编码格式的字符串 echo "\u{aa}"; echo "\u{0000aa}"; echo "\u{9999}"; 8、Closure::call() 简短干练的暂时绑定一个方法到对象上闭包并调用它。 <?php class A {private $x = 1;} // PHP 7 之前版本的代码 $getXCB = function() {return $this->x;}; $getX = $getXCB->bindTo(new A, 'A'); // 中间层闭包 echo $getX(); // PHP 7+ 及更高版本的代码 $getX = function() {return $this->x;}; echo $getX->call(new A); 9、为unserialize()提供过滤 通过白名单的方式来防止潜在的代码注入。 <?php // 将所有的对象都转换为 __PHP_Incomplete_Class 对象 $data = unserialize($foo, ["allowed_classes" => false]); // 将除 MyClass 和 MyClass2 之外的所有对象都转换为 __PHP_Incomplete_Class 对象 $data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]); // 默认情况下所有的类都是可接受的,等同于省略第二个参数 $data = unserialize($foo, ["allowed_classes" => true]); 10、断言 assert()现在是一个语言结构,它允许第一个参数是一个表达式,而不仅仅是一个待计算的 string或一个待测试的boolean。 <?php ini_set('assert.exception', 1); class CustomError extends AssertionError {} assert(false, new CustomError('Some error message')); 11、Group use declarations 从同一 namespace 导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。 // PHP 7+ 及更高版本的代码 use some\namespace\{ClassA, ClassB, ClassC as C}; use function some\namespace\{fn_a, fn_b, fn_c}; use const some\namespace\{ConstA, ConstB, ConstC}; 12、生成器可以返回表达式 允许在生成器函数中通过使用 return 语法来返回一个表达式 (但是不允许返回引用值), 可以通过调用 Generator::getReturn() 方法来获取生成器的返回值, 但是这个方法只能在生成器完成产生工作以后调用一次。 <?php $gen = (function() { yield 1; yield 2; return 3; })(); foreach ($gen as $val) { echo $val, PHP_EOL; } echo $gen->getReturn(), PHP_EOL; 13、生成器委托 只需在最外层生成器中使用 yield from, 就可以把一个生成器自动委派给其他的生成器, Traversable 对象或者 array。 <?php function gen() { yield 1; yield 2; yield from gen2(); } function gen2() { yield 3; yield 4; } foreach (gen() as $val) { echo $val, PHP_EOL; } 14、整数除法函数 intdiv() 进行 整数的除法运算。 <?php var_dump(intdiv(10, 3)); 15、可以使用 list() 函数来展开实现了 ArrayAccess 接口的对象
==============PHP5.3==
1.支持命名空间(namespace) 2.通过static关键字,实现方法的延迟静态绑定 3.支持goto语句 4. 支持闭包匿名函数或Lambda函数array_map()或array_walk()等函数的回调函数 5. 两个魔术方法__callStatic()和__invoke() 6. 新增Nowdoc语法结构 7. const 关键字 8.三元省 expr1 ?: expr3 9. 静态成员或静态方法支持 10.支持try…catch
=========PHP5.4========
1新增traits Traits提供了一种灵活的代码重用机制 2. 数组【】支持写法 3.支持函数方法数组化访问 5.加入webserver 6上传进度支持 $_SESSION[“upload_progress_name”] 7json_encode 可中文输出 8二进制直接量 9函数的参数类型 10. 废除了register_globals、 magic_quotes、 allow_call_time_pass_reference以及安全模式等等。 11. 早期 在早期版本中,你可以在函数调用时,在参数前添加&修饰符来指明参数变量按引用传递,你只需要在函数声明时指定按引用传递即可
==========Php5.5=======
新增Generator生成器yield 2. try…catch 新增了finally 3. foreach中支持嵌套list()结构 4..empty() 支持传入表达式,而不仅是一个变量 5. 非变量array或string也能支持下标访问 <?php echo array(1, 2, 3)[0]; echo [1, 2, 3][0]; echo "foobar"[0]; // 输出:11f 6. 新增密码哈希API password_hash password_verify 7. 新增 boolval() 函数 8. 新增 array_column() 函数二维数组中指定的列
======Php5.6====
1增强了const 常量 以前只能使用固定的值,现在允许常量计算,允许使用包含数字、字符串字面值和常量的表达式结果定义const常量,常量的值也可以为一个数组 2支持使用 … 运算符定义变长参数函数 实现变长 3 ** 进行幂运算 printf(2 ** 3); // 8 $a **= 3; 4命名空间 use 操作符支持函数和常量的导入 对应的结构为 use function 和 use const。 5. 解包功能 6. 上传超过2G的大文件 7. php://input 可以被复用 在 PHP 5.6 之前 php://input 打开的数据流只能读取一次; 数据流不支持 seek 操作 现在依赖于 SAPI 的实现,请求体数据被保存的时候, 它可以打开另一个 php://input 数据流并重新读取。 通常情况下,这种情况只是针对 POST 请求,而不是其他请求方式
分类: PHP