PHPのお勉強!

PHP TOP

新機能

スカラー型宣言

スカラー 型宣言 には二つの方式があります。デフォルトの自動変換(coercive) モードと、 厳密に判断する strict モードです。 パラメータとして、 文字列 (string)、整数 (int)、浮動小数点数 (float)、boolean (bool) といった型をいずれかの方式で強制できるようになりました。 これらは、PHP 5 で導入された型宣言 (クラス名やインターフェイス、配列そして callable) を強化するものです。

<?php
// デフォルトのモード
function sumOfInts(int ...$ints)
{
return
array_sum($ints);
}

var_dump(sumOfInts(2, '3', 4.1));

上の例の出力は以下となります。

int(9)

strict モードを有効にするには、ファイルの先頭に declare ディレクティブを置く必要があります。 つまり、スカラー型を厳密に扱うかどうかは、ファイル単位で定めるということです。 このディレクティブは、パラメータの型宣言だけでなく、関数の戻り値の型 (戻り値の型宣言を参照ください) や PHP の標準関数、そして拡張モジュールの関数にも影響を及ぼします。

スカラー型宣言に関するドキュメントやサンプルについては、 型宣言 を参照ください。

戻り値の型宣言

PHP 7 では、 戻り値の型宣言 もできるようになりました。 引数の型宣言 と同様に、戻り値の型宣言では、関数が戻す値がどの型になるかを宣言します。 戻り値の型宣言で使える は、引数の型宣言で使えるものと同じです。

<?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]));

上の例の出力は以下となります。

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

詳細なドキュメントやサンプルについては、 戻り値の型宣言. を参照ください。

Null 合体演算子

null 合体演算子 (??) がシンタックスシュガーとして追加されました。 三項演算子と isset() を組み合わせる よくありがちなパターンを、より簡単に書くためのものです。 この演算子は、もし第一オペランドが非 null の値であればそれを返し、 そうでない場合は第二オペランドを返します。

<?php
// $_GET['user'] を取得します。もし存在しない場合は
// 'nobody' を用います。
$username = $_GET['user'] ?? 'nobody';
// 上のコードは、次のコードと同じ意味です。
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// 合体演算子を連結することもできます。次のように書くと、
// $_GET['user']、$_POST['user'] そして 'nobody'
// の順に調べて、非 &null; が定義されている最初の値を返します。
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

宇宙船演算子

宇宙船演算子は、二つの式を比較するために使うものです。 $a$b より大きい場合は 1、 $a$b が等しい場合は 0、 $a$b より小さい場合は -1 をそれぞれ返します。 比較の際には、 PHP 型の比較表 のルールを用います。

<?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
?>

define() を用いた配列定数の定義

define() で配列の定数を定義できるようになりました。 PHP 5.6 までのバージョンでは、配列の定数は const でしか定義できませんでした。

<?php
define
('ANIMALS', [
'dog',
'cat',
'bird'
]);

echo
ANIMALS[1]; // "cat" と出力します
?>

無名クラス

無名クラスをサポートするようになりました。new class を使って利用します。 その場限りの使い捨てのオブジェクトなどで、完全なクラス定義のかわりとして使えます。

<?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());
?>

上の例の出力は以下となります。

object(class@anonymous)#2 (0) {
}

詳細なドキュメントは 無名クラス を参照ください。

Unicode コードポイントエスケープ構文

Unicode のコードポイントを十六進形式で受け取って、 それを UTF-8 で (ダブルクォートで囲まれた文字列あるいはヒアドキュメントとして) 出力します。 妥当な形式のコードポイントならあらゆるものが使えます。先頭のゼロは省略してもかまいません。

<?php

echo "\u{aa}", PHP_EOL;
echo
"\u{0000aa}", PHP_EOL;

echo
"\u{9999}", PHP_EOL;

echo <<<EOT
\u{01f418}
EOT;

?>

上の例の出力は以下となります。

a
a (先頭のゼロを省略せずに書いても、前の行と同じ結果になります)
香

Closure::call()

Closure::call() は、オブジェクトのスコープをクロージャに一時的に束縛して実行するための、 より高性能で簡潔な方法です。

<?php
class A {private $x = 1;}

// 以前のバージョンのコード
$getX = function() {return $this->x;};
$getXCB = $getX->bindTo(new A, 'A'); // 中間クロージャが必要
echo $getXCB();

// PHP 7 以降でのコード
$getX = function() {return $this->x;};
echo
$getX->call(new A);

上の例の出力は以下となります。

1
1

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]);

IntlChar

ICU のさらなる機能を利用するために、新しく IntlChar クラスが追加されました。このクラスには数々の static メソッドと定数が定義されており、 これらを使って Unicode の文字を操作できます。

<?php

printf
('%x', IntlChar::CODEPOINT_MAX);
echo
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

上の例の出力は以下となります。

10ffff
COMMERCIAL AT
bool(true)

このクラスを使うには、Intl 拡張モジュールをインストールしなければいけません。

Expectation

Expectations は、かつての assert() 関数を、下位互換性を保ったまま拡張したものです。 これを用いると、コストをかけずに実運用コードの中にアサーションを組み込めます。 そして、アサーションが失敗した際に自作の例外をスローできるようになります。

これまでの API も下位互換性を保つために維持されていますが、 assert() は言語構造となりました。 最初のパラメータには、単に評価対象の文字列や bool 値を指定するだけではなく、式を渡せます。

<?php
ini_set
('assert.exception', 1);

class
CustomError extends AssertionError {}

assert(false, new CustomError('Some error message'));
?>

上の例の出力は以下となります。

Fatal error: Uncaught CustomError: Some error message

開発環境および運用環境での設定方法などの詳細については、 言語構造 assert() のマニュアルを参照ください。

use 宣言のグループ化

複数のクラスや関数そして定数を同じ namespace からインポートする際に、 単一の use 文にまとめられるようになりました。

<?php
// 以前のバージョンのコード
use some\namespace\ClassA;
use
some\namespace\ClassB;
use
some\namespace\ClassC as C;

use function
some\namespace\fn_a;
use function
some\namespace\fn_b;
use function
some\namespace\fn_c;

use const
some\namespace\ConstA;
use const
some\namespace\ConstB;
use const
some\namespace\ConstC;

// 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};
?>

ジェネレータでの return

PHP 5.5 で導入されたジェネレータの機能拡張です。 ジェネレータの内部で 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;

上の例の出力は以下となります。

1
2
3

ジェネレータの最終値を明示的に返せる機能は、あれば便利なものです。 ジェネレータを実行したクライアント側のコードが、 ジェネレータが最後に返す値 (何らかのコルーチンの計算結果) を特別扱いできるようになるからです。 「取得した値が最後の値かどうかをまず調べて、最後であれば特別扱いする」 という処理をクライアント側で書くよりは、ずっとシンプルになります。

ジェネレータの委譲

ジェネレータを、別のジェネレータや Traversable オブジェクトそして配列に委譲できるようになりました。 外側のジェネレータに決まり文句を書いたりする必要はなく、単に yield from 構文を使うだけです。

<?php
function gen()
{
yield
1;
yield
2;
yield from
gen2();
}

function
gen2()
{
yield
3;
yield
4;
}

foreach (
gen() as $val)
{
echo
$val, PHP_EOL;
}
?>

上の例の出力は以下となります。

1
2
3
4

intdiv() による整数の除算

新しい intdiv() 関数は、 オペランドに対して整数の除算を行い、その結果を返します。

<?php
var_dump
(intdiv(10, 3));
?>

上の例の出力は以下となります。

int(3)

セッションのオプション

session_start() にオプションの配列を渡せるようになりました。 これは、php.ini などで設定した session 設定ディレクティブ を上書きします。

新たな設定オプション session.lazy_write をサポートするようになりました。これはデフォルトで有効になっており、 セッションのデータが書き換えられたときにだけセッションファイルを上書きします。 また、read_and_close も追加されました。 このオプションは session_start() だけに渡せるもので、 セッションデータを読み込んだら何も変更せずその場でクローズするよう指示します。

たとえば、 session.cache_limiterprivate にして、読み込んだセッションをすぐにクローズさせるには次のようにします。

<?php
session_start
([
'cache_limiter' => 'private',
'read_and_close' => true,
]);
?>