PHP 8:Windows版のイントール/Apacheと連携/特長

(1/1)
PHP 8.0
PHP 8.0が、2020年(令和2年)11月26日に正式版がリリースされた。

目玉機能は、頻繁に実行されるコードをコンパイルしておくことでプログラムの実行速度を向上させる JIT の搭載だ。プログラムによるが、PHP 7.xに比べて1.5~3倍の高速化が見込まれる。
その他、コンストラクタの記述テンプレート簡素化や、Switch~Case文に代わるMatch文など、コーディングのストレスを軽減する改良が多い。
ただし、比較演算子の挙動が変更になるなど、一部の機能で後方互換性が失われるため、PHP 8.0 への移行には多少のコード変更が必要となるかもしれない。

2020年(令和2年)7月29日、マイクロソフトは PHP 8.0 から[https://news-web.php.net/php.internals/110907「PHP for Windows」をサポートする予定はない]と発表した。IISで動作するPHPは、PHP 7.4(セキュリティサポート期限は2022年11月28日)が最後となる。

PHP 8.0 のアクティブサポート期限は2022年(令和4年)11月26日、セキュリティサポート期限は2023年(令和5年)11月26日である。

目次

インストール手順

ここでは、Windows 10 に PHP 8.0 をインストールする手順を紹介する。

macOSへのインストールは公式マニュアルを、Linuxへのインストールも公式マニュアルを参照していただきたい。

Windows 版 PHP の入手方法

Windows版 PHP 8.0 は、公式サイト からダウンロードできる。

ここではWindows版 PHP 8.0.0 の 64ビット版をインストールする。後述する Apache 2.4系はマルチスレッドに対応しているので、Thread Safeである "VS16 x64 Thread Safe (2020-Nov-24 22:49:03)" をダウンロードしておこう。新バージョンがリリースされると、このファイル名は変化するので注意されたい。PHP 7.xとの共存を考え、ZIP版をダウンロードするといいだろう。

圧縮ファイルの解凍

ZIPファイルを "PHP8.0" という名前のフォルダに解凍し、"C:\Program Files"の下にコピーする。これだけで、コマンドライン版(Command Line Interface;CLI版)のPHPが利用できるようになる。
CLI版を多用することが多ければ、"C:\Program Files\PHP8.0" にPATHを通しておくとよいだろう。

異なるフォルダに解凍するだけで、PHP7.xと PHP 8.0 の共存は可能である。
CLI版を使い分けるようにするには、バージョン7の "php.exe" を "php7.exe" とリネームしておくといいだろう。
PHP8 コマンドライン
"C:\Program Files\PHP8.0" に移動して"php -h"としてヘルプを表示させたとことが左図である。

Javaアプレットのように、PHPはスタンドアロンでも実行することができるが、Webサーバと組み合わせることで用途が広がる。

Apacheと連携

ここでは、Windows 10 上で動作しているWebサーバ Apache 2.4(64ビット版)に PHP 8.0 を連携する手順を紹介する。

Visual Studio 2019 の Visual C++ 再頒布可能パッケージ

連携には「Visual Studio 2019 の Microsoft Visual C++ 再頒布可能パッケージ」が必要になる。
マイクロソフトのダウンロードサイト > すべてのダウンロード > その他のツールとフレームワーク > Visual Studio 2019 の Microsoft Visual C++ 再頒布可能パッケージ」を選んでダウンロードし、インストールしてほしい。

PHP側の準備

次に、/PHP8.0 ディレクトリにある "php.ini-development" をコピーして "php.ini" にリネームする。PHP 7.x以前とは異なり、"C:\Windows" フォルダにコピーするのではない。

php.iniの調整(UTF-8の場合)

日本語(UTF-8)でスクリプトを書くために、php.ini の設定値を下記のように調整する。extensionの値が PHP 7.x以前と異なる点に留意。
UTF-8でスクリプトを書く場合
; 変更
date.timezone = "Asia/Tokyo"

; 変更
default_charset = "UTF-8"

; 変更(PHPをインストールしたディレクトリを指定)
extension_dir = "C:\Program Files\PHP8.0\ext"

; 必要に応じてextensionのコメントを外す
extension=curl
extension=fileinfo
extension=gd
extension=mbstring
extension=exif
extension=openssl
extension=pdo_mysql
extension=pdo_sqlite
extension=sqlite3

; 変更
; 初期値でコメントアウトしてあるので注意
mbstring.language = Japanese

Apache側の調整

httpd.conf に以下の行を加える。cURLsqlite3 を使う想定。モジュール名が PHP 7.x と異なり "php_module" になっている点に留意。
PHP 8
LoadFile  "C:/Program Files/PHP8.0/php8ts.dll"
LoadFile  "C:/Program Files/PHP8.0/libssh2.dll"
LoadFile  "C:/Program Files/PHP8.0/nghttp2.dll"
LoadFile  "C:/Program Files/PHP8.0/libcrypto-1_1-x64.dll"
LoadFile  "C:/Program Files/PHP8.0/libssl-1_1-x64.dll"
LoadFile  "C:/Program Files/PHP8.0/libsqlite3.dll"
LoadModule  php_module "C:/Program Files/PHP8.0/php8apache2_4.dll"
AddType    application/x-httpd-php  .php
OpenSSLや cURL関数を利用する場合は、以下の3つのファイルを Apacheがインストールされている binフォルダへコピーする。
  • libcrypto-1_1-x64.dll
  • libssh2.dll
  • libssl-1_1-x64.dll
  • nghttp2.dll


Apacheを再起動させる。エラーメッセージが出なければ、PHPが利用できるようになる。

ブラウザから動作確認

最後に、PHPが動作していることを確認する。
以下のスクリプトファイルを phpinfo.php という名前で、Apacheが参照できるディレクトリにセーブする。
PHP 8
<?php
    phpinfo();
?>
Webブラウザを開いて、このスクリプトを実行する(例:http://localhost/pahoo/phpinfo.php)。
下図のようにPHPのバージョン番号などが表示されれば正常に動作している。
PHP 8.0

JITによる高速化

PHP 8.0
これまでPHPは、リクエストがあるたびにソースコードを opcode に変換し逐次実行するインタプリタ型のプログラミング言語だった。
PHP 5.5では OPcache が導入され、opcode をメモリに保存しておき、次のリクエストでも使い回すようにして処理速度をアップした。

PHP 8 では、トレーシングJITと関数単位のJITの2種類の JIT が組み込まれた。JIT は、opcode がCPUが直接実行できるネイティブコードに変換する。さらに、変換されたネイティブコードは次のリクエストでも使い回すことができる。
その結果、トレーシングJITを使った場合のパフォーマンスはJITなしの場合と比較してベンチマークでおよそ3倍、実行時間が長いアプリケーションでおよそ1.5~2倍となった。
もはやコンパイル型プログラミング言語といっていいだろう。

名前付き引数

PHP 7
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);
PHP 8
htmlspecialchars($string, double_encode: false);
関数やメソッド呼び出し時にどの引数にどの値を渡すのかを名前で指定できる名前付き引数(Named arguments)が実装された。これにより、必要な変数のみ指定し、不要な変数を省略することができる。

属性

PHP 7
class PostsController
{
   
#[Route("/api/posts/{id}", methods: ["GET"])]
   
public function get($id) { /* ... */ }
}
PHP 8
class PostsController
{
   
#[Route("/api/posts/{id}", methods: ["GET"])]
   
public function get($id) { /* ... */ }
}
PHPDocの代わりにPHP本来の構文でメタデータを記述し、ドキュメントを生成できるようになった。

コンストラクタの記述テンプレート簡素化

PHP 7
class Point {
  public
float $x;
  public
float $y;
  public
float $z;

  public function
__construct(
   
float $x = 0.0,
   
float $y = 0.0,
   
float $z = 0.0,
  ) {
   
$this->x = $x;
   
$this->y = $y;
   
$this->z = $z;
  }
}
PHP 8
class Point {
  public function
__construct(
    public
float $x = 0.0,
    public
float $y = 0.0,
    public
float $z = 0.0,
  ) {}
}
コンストラクタのテンプレートをより簡単に記述することができるようになった。

ユニオン型

PHP 7
class Number {
 
/** @var int|float */
 
private $number;

 
/**
   * @param float|int $number
   */
 
public function __construct($number) {
   
$this->number = $number;
  }
}

new
Number('NaN'); // Ok
PHP 8
class Number {
  public function
__construct(
    private
int|float $number
 
) {}
}

new
Number('NaN'); // TypeError
複数の型の組み合わせに対応できるユニオン型(Union types)が実装された。

Match文

PHP 7
switch (8.0) {
  case
'8.0':
   
$result = "Oh no!";
    break;
  case
8.0:
   
$result = "This is what I expected";
    break;
}
echo
$result;
//> Oh no!
PHP 8
echo match (8.0) {
 
'8.0' => "Oh no!",
 
8.0 => "This is what I expected",
};
//> This is what I expected
PHP 7まで Switch-Case文 で記述していた判定式を、より簡単に記述できる Match文(Match expression)を利用できるようになった。

Nullsafe演算子

PHP 7
$country null;

if (
$session !== null) {
 
$user = $session->user;

  if (
$user !== null) {
   
$address = $user->getAddress();
 
    if (
$address !== null) {
     
$country = $address->country;
    }
  }
}
PHP 8
$country = $session?->user?->getAddress()?->country;
"?" で変数をつなげることでチェーン全体のNull判定を行える Nullsafe演算子(Nullsafe operator)が導入された。これにより、個別の変数に対してNull判定を行う必要がなくなる。

比較演算子の挙動変更

PHP 7
0 == 'foobar' // true
PHP 8
0 == 'foobar' // false
PHP 8 では比較演算子の挙動が見直され、数値文字列を比較する際に数値比較を使用するようになった。それ以外の場合は、数値を文字列に変換して文字列比較を使用する。

一貫した内部関数の型エラー

PHP 7
strlen([]); // Warning: strlen() expects parameter 1 to be string, array given

array_chunk([], -1); // Warning: array_chunk(): Size parameter expected to be greater than 0
PHP 8
strlen([]); // TypeError: strlen(): Argument #1 ($str) must be of type string, array given

array_chunk([], -1); // ValueError: array_chunk(): Argument #2 ($length) must be greater than 0
ほとんどの内部関数は、変数の検証に失敗した場合にエラー例外を返すようになった。

参考サイト

(この項おわり)
header