[翻訳] PHP7 の紹介: 新しい機能と削除された機能
/** * 原文出处:https://www.toptal.com/php/php-7-performance-features * @author dogstar.huang <chanzonghuang@gmail.com> 2016-03-13 */
PHP の世界で、2015 年の最もエキサイティングなニュースの 1 つは、PHP のリリースです。バージョン 7 は、最後のメジャー バージョンである PHP 5 から 10 年後にリリースされます。 大きな前進である PHP 7 では、多数の新機能とパフォーマンスのアップグレードが導入されています。
ただし、一部の互換性の問題により、古い非推奨の機能も削除されるため、古いアプリを新しいバージョンに移行することがより困難になります。 既存のアプリケーションを PHP 7 に移行する場合、または新しいアプリケーションを構築する場合は、このガイドが何を期待するのかについての簡単なガイドとして役立ちます。
最近仕事で PHP を使用していない場合は、PHP 6 で何が起こったのか疑問に思っているかもしれません。なぜ PHP 5 から PHP 7 に直接ジャンプしたのですか? まあ、簡単に言えば、PHP 6 は失敗しました。 PHP は主に Web サイト開発に使用され、Web サイトには Unicode が必要であるため、バージョン 6 の主な機能は Unicode のネイティブ サポートであるため、PHP に Unicode を導入する動きは理にかなっています。
このアイデアは、完全な Unicode サポートをコアに組み込むことです。これにより、面白い絵文字を変数名や関数名として使用する機能から、強力な国際文字機能に至るまで、言語に拡張機能がもたらされたでしょう。たとえば、英語以外の言語で大文字と小文字が使用されている場合や、中国語の文字名を英語に変換する必要がある場合などです。
PHP 6 は野心的ですが、ひどいものです。このため、このプロセスは PHP 7 で終了し、直接 6 に進みます。
残念ながら、この野心的な計画は予想よりも大きな問題であることが判明しました。コアと重要な拡張機能の両方で Unicode をサポートするには、コード ベースの多くを移植する必要がありましたが、これは退屈で複雑であることが判明しました。これにより、言語の他の機能の開発が遅れ、その過程で多くの PHP 開発者が挫折しました。さらなる障害の出現により、ネイティブ Unicode サポートの開発への関心が大幅に低下し、最終的にプロジェクトは放棄されました。
書籍や記事などのリソースは PHP 6 とその Unicode サポート用に編集されているため、混乱を避けるために新しいバージョンは PHP 7 と名付けられます。
とにかく、過去を振り返るのは難しいので、PHP 7 がもたらすものを見てみましょう。
ほぼすべてのアップデートにより、わずかなパフォーマンスのアップグレードが期待されます。ただし、今回の PHP は以前のバージョンよりも重要な改善をもたらし、純粋なパフォーマンスが PHP 7 の最も魅力的な機能になっています。これは、Zend Engine 自体の内部をキャプチャする「PHPNG」プロジェクトの一部として提供されます。
内部データ構造をリファクタリングし、抽象構文ツリー (AST) 形式でのコード コンパイルに中間ステップを追加することにより、優れたパフォーマンスとより効率的なメモリ割り当てが実現します。 数値自体は非常に有望に見えます。実際のアプリケーションで実行されたベンチマークでは、PHP 7 は PHP 5.6 の平均 2 倍高速で、リクエスト中のメモリ消費量が 50% 少ないことが示されており、PHP 7 は Facebook HHVM となり、JIT コンパイラーの強力なライバルとなっています。一般的な CMS とフレームワークについては、Zend の図を参照してください。
PHP 7 は見た目も使い慣れていますが、パフォーマンスが向上するように調整されています。洗練された Zend エンジンは、結果として得られるパフォーマンスに大きな違いをもたらしました。
PHP を中心にマイクロサービスを構築できるため、メモリ消費量が削減され、より小型のマシンでリクエストをより適切に処理できるようになります。特に AST 実装に対する内部変更により、パフォーマンスをさらに向上させる将来の最適化の可能性も広がります。将来のリリースでは、新しい内部 JIT 実装が検討されています。
PHP 7 には、新しい構文機能が付属しています。言語自体の機能を拡張しない場合、コードを書くのが楽しくなり、見た目も楽しくなる、より良い、または簡単な方法が提供されます。
ここで、同じ名前空間からのクラス インポート宣言を 1 つの use 行にグループ化することを簡素化できます。これは、宣言を意味のある方法で整列させたり、単にファイル内のバイト数を節約したりするのに役立ちます。
use Framework\Module\Foo;use Framework\Module\Bar;use Framework\Module\Baz;
PHP 7 では次のように使用できます:
use Framework\Module\{Foo, Bar, Baz};
または複数行のスタイルを希望する場合:
use Framework\Module{ Foo, Bar, Baz};
これは、PHP プログラミングにおける一般的な問題を解決します。これは、ある変数の値を別の変数に代入する場合、後者が実際に設定されている場合は、そうでない場合は別の値を指定します。 通常、ユーザーから提供された入力を処理するときに使用されます。
PHP 7 より前:
if (isset($foo)) { $bar = $foo;} else { $bar = 'default'; // we would give $bar the value 'default' if $foo is NULL}
PHP 7 以降:
$bar = $foo ?? 'default';
次のように複数の変数を連結することもできます:
$bar = $foo ?? $baz ?? 'default';
飞船操作符<=>允许有三种方式来比较两个值,不仅意味着如果他们相等,还包括哪一个更大,通过返回1,0或-1的不等式。
我们可以根据值的不同做出不同的动作:
switch ($bar <=> $foo) { case 0: echo '$bar and $foo are equal'; case -1: echo '$foo is bigger'; case 1: echo '$bar is bigger';}
对比的值可以是整型int,浮点数float,字符串string甚至数组array。关于不同的值是如何相互对比的更多信息请查看文档:https://wiki.php.net/rfc/combined-comparison-operator
当然PHP 7也带来了新的令人兴奋的功能。
通过添加这四个标量类型:;整型(int),浮点数(float),布尔值(bool)和字符串(string)和尽可能的参数类型, PHP 7扩展了先前在方法里(类,接口和数组)的参数类型声明。
更进一步,我们可以可选地指定方法和函数返回哪些类型。支持的类型有 bool,int,float,string,array,callable, 类名或接口名,self和parent(针对类方法) 。
class Calculator{ // We declare that the parameters provided are of type integer public function addTwoInts(int $x, int $y): int { return $x + $y; // We also explicitly say that this method will return an integer }}
类型声明有助于构建更强壮的应用并且避免从函数传递或返回错误的值。其他好外包括静态代码分析和当缺少文档块时提供更好的代码库提示的IDE。
既然PHP是一个弱类型语言,参数和返回类型的值基于上下文投射。如果在一个函数中传递的值“3”并且声明参数类型为int,解释器会把它作为 一个整数来接收而不会抛出任何错误。如果你不想要这点,可以通过添加一个declare指示开启strict mode。
declare(strict_types=1);
这设置在每个文件的基础上,作为一个全局的选项划分代码库为和全局严格开启进行构建和全局严格开关关闭时构建,导致当我们从两者合并代码时出 现了非期望的行为。
通过添加的引擎异常,由脚本终端导致的致命错误可以轻松捕捉并处理。
例如调用一个不存在的方法的错误不会终止脚本,取而代之的是他们会抛出一个可以被try catch块处理的异常,这点提高了你应用的错误处理。 这对于诸如应用、服务和进程是重要的因为致命错误需要他们重新启动。在PHPUNit的测试也会变得更可用因为致命错误之前会丢掉整个测试套件。 异常,而不是错误,会在每一个测试案例基础上处理。
PHP 7看起来和感觉都熟悉,但是它为性能作了调整。精制的Zend引擎和得到的结果性能产生了巨大的变化。
PHP 7根据可能触发的错误类型添加了若干新的异常类。为了维护版本之间的兼容性,添加了一个新的接口Throwable,可以被引擎异常和用户异 常这两者实现。为了避免引擎异常扩展基础异常类这是有需要的,导致更老的代码捕捉当时还没有的异常。
在PHP 7前这样会以一个致命错误终止脚本:
try { thisFunctionDoesNotEvenExist();} catch (\EngineException $e) { // Clean things up and log error echo $e->getMessage();}
匿名类是匿名函数的表兄弟,你可以在一个简短的实例中使用。匿名类创建简单并且像一个正常的对象那样使用即可。以下是来自文档的一个示例。
PHP 7前
class MyLogger { public function log($msg) { print_r($msg . "\n"); }}$pusher->setLogger( new MyLogger() );
使用匿名类:
$pusher->setLogger(new class { public function log($msg) { print_r($msg . "\n"); }});
匿名类在单元测试中很有用,特别在模拟测试对象和服务时。这有利于我们通过创建一个简单的对象并提供我们想要模拟的接口来避免重量级的模拟库和框架。
添加了两个生成加密安全字符串和整数的新函数。
random_bytes(int $len);
返回一个长度为$len的随机字符串。
random_int(int $min, int $max);
返回一个$min和$max之间的数字。
在PHP 7之前,不像其他很多语言,PHP没有一种转义字符语中Unicode代码点的方式。这个功能添加了序列\u以产生使用他们UTF-8代码点的字符。 这样相比直接插入字符更好,使得更好处理不可见的字符和有相同图表展示但意义不同的字符。
echo "\u{1F602}"; // outputs ??
注意这会使用\u断开已有的代码因为它改变了行为。
在PHP的生成器也得到了一些优雅额外的特性。现在,生成器有一个可用于跟在迭代后允许输出一个最终值的返回声明。这点可用于检测生成器已经执行且没有错误 并且允许调用生成的代码处理大量适当的场景。
再进一步,生成器可以从其他生成器返回和yield表达式。这使得他们可以把复杂的操作划分为更简单和模块化的单元。
function genA() { yield 2; yield 3; yield 4;}function genB() { yield 1; yield from genA(); // 'genA' gets called here and iterated over yield 5; return 'success'; // This is a final result we can check later}foreach (genB() as $val) { echo "\n $val"; // This will output values 1 to 5 in order}$genB()->getReturn(); // This should return 'success' when there are no errors.
期望是在维护向后兼容性时对assert()的一个增强。他们允许在生产代码中零消耗的断言,并提供当断言失败时抛出自定义异常的能力,这一点在开发中很有帮助。
assert()成为了PHP 7中的一个语言构造。 断言应该只在开发和测试环境中用于调试目的。为了配置它的行为,提供了两个新的标题给我们。
这次主发布的介绍带来了改变/升级老功能的一个机遇,或者甚至如果被认为过于古老或者已废弃有一段时间的话就移除他们。这样的改变会在老的应用引入兼容性的中断。
另外从这次版本跳跃而引发的一个问题是你所依赖的重要类库和框架可能还没升级到支持最新的版本。PHP团队已尝试着把这些新的改变尽可能向后兼容并且 让迁移到新版本尽可能少点痛苦。更新和更持续更新的应用可以发现转移到新版本更容易,而老的应用则不得不决定是否收益大于成本,并且可能选择不作升级。
大部分中断都是轻微的并且可以轻松迁移,而另外一些可能要更大的努力的更多的时间。基本上来讲,如果在安装PHP 7前在你的应用中警告,很可能会有中断应用直到修复的错误。 你有被警告过了,对吗?
最重要地,诸如mysql扩展(但你应该不会在第一个地方使用这个,是吗?)这样老的和弃用的SAPI已被移除。完整的扩展和特性移除可以在这里 和这里查看这个RFC。
此外,其他的SAPI正在移植到PHP 7。
从PHP 7起很多老的SAPI和扩展已被丢弃。我们在想他们应该不会有人想起。
这个更新为变量-变量结构的一致性做了一些修改。这允许了更先进带变量的表达式但也在其他一些场景中引入了变化,如下所示。
// old meaning // new meaning$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()
这会中断应用访问像这些变量的行为。另一方面,你可以做一些像这样奇妙的东西:
// Nested ()foo()(); // Calls the return of foo()$foo->bar()();// IIFE syntax like JavaScript(function() { // Function body})();// Nested ::$foo::$bar::$baz
<% ... %>,<%= ... %>,这类开/关标签已被移除并不再有效。用有效的替换这些很容易,但是你用这些来干嘛,怪咖?
由于诸如参数和返回类型这样的附加项,类,接口和特征不再允许有以下名称:
对于用到他们的已有应用和类库会引起中断,但修复很容易。同样,尽管不会引起任何错误并且是有效的,以下这些也不应该使用因为他们为将来使用而保留:
克制使用他们能让你免于在未来再作调整。
对于会中断兼容的改变的完全列表,请查看这份文档。
你也可以使用php7cc,它会检查你的代码并可以发现如果你转称到PHP 7可能会出来的任何潜在的问题。 但当然,没有比安装PHP 7并且自己亲自看一下更好的方式了。
大量托管的服务已开始着手添加对PHP 7的支持。这对于共享托管供应商是一个好消息,因为所得的性能允许他们在现有硬件提高网站客户数量, 降低运营费用,提高利润率。而对于客户端本身,他们期望在这样的条件下不应该有太大的提高,但出于公平而,无论如何共享托管不是一个面向性能的选择。
一方、仮想プライベートプロバイダーまたは専用プロバイダーを提供するサービスは、このパフォーマンスの向上から大きな恩恵を受けるでしょう。 Heroku などの一部の PHP 7 対応 PaaS サービスは早くからオンラインになっていますが、AWS Beanstalk や Oracle の OpenShift などの他のサービスは遅れています。 PaaS プロバイダーのサイトをチェックして、PHP 7 がすでにサポートされているか、または間もなくサポートされるかどうかを確認してください。
もちろん、IaaS を使用すると、ハードウェアを制御し、PHP 7 をインストール (または必要に応じてコンパイル) できます。 PHP 7 のパッケージは、主流の IaaS 環境ですでに利用可能です。
インフラストラクチャの互換性に加えて、潜在的なソフトウェア互換性の問題にも注意する必要があります。 WordPress、Joomla、Drupal などの一般的なコンテンツ管理システム (CMS) の最新バージョンでは、PHP 7 のサポートが追加されました。 Symfony や Laravel などの主流フレームワークも完全にサポートされています。
ただし、注意という言葉について言及する時期が来ました。このサポートは、アドオン、プラグイン、パッケージ、または CMS やフレームワークがそれらを呼び出す形式のサードパーティ コードには拡張されません。互換性の問題が発生する可能性があるため、すべてが PHP 7 に対応できるようにするのはあなたの責任です。
PHP 7 のリリースにより、古いコードが削除され、将来の新機能とパフォーマンスのアップグレードへの道が開かれます。そのため、PHP は近いうちにさらなるパフォーマンスの最適化が行われることが予想されます。過去のリリースには互換性の問題がいくつかありましたが、ほとんどの問題は簡単に解決できます。
ライブラリとフレームワークは現在、コードを PHP 7 に移行しているため、最新バージョンを入手してください。ぜひ試してみて、その結果を自分の目で確認することをお勧めします。おそらくあなたのものはすでに互換性があり、使用されるのを待っているだけでなく、PHP 7 の恩恵を受けているはずです。
参考: 動作しない PHP をデバッグする前に、PHP 開発者が犯す最も一般的な 10 の間違いのリストを参照してください