みなさんこんにちは
いつの間にかDockerの公式コンテナの正式なlatestバージョンが7.1になりました。
私のようにソースコードのビルドめんどくさいマンはdockerイメージとして配布されると、とても導入しやすくなるので、嬉しい限りなのです。
そんなわけで、せっかくPHPのdockerイメージをバージョンアップしたので、動作確認をしてみようと思います。
PHPのマニュアルサイトは異様なほど充実しており、それを見ただけで、どんな変更があるかわかるのが便利です。
そこで、マニュアルにある新機能をソースコードをパクりながら動作確認していきましょう。
検証自体は他の人が先にやってたりしますが、自分でも動かしてみて、実行結果を見ていくのもいいんじゃないかって思いました。
各新機能の動作確認
追加された新機能の中で、面白いものをピックアップしていきます。
nullable
なんかちょっと前に流行ったnullableがPHPにも登場です。
「null安全でない言語なんてもはや言語ではないわ!」「nullable最高や!」みたいなエンジニアにも、「あ、PHPもnullableありますよ!」っていえますな。
これは関数の引数もしくは関数の返り値に型を指定した際、引数の値にnullを許すというものです。
書式は簡単で、指定した方の先頭に「?」を付け加えるだけです。
サンプルコードを上述のマニュアルから持ってきますが。。。現時点(2016/12/15)では、そのままコピると関数の二重定義で動かないので、ちょっとだけ変えて動作確認してみましょう。
<?php
function testReturn(): ?string
{
return 'elePHPant';
}
var_dump(testReturn());
function testReturn2(): ?string
{
return null;
}
var_dump(testReturn2());
function test(?string $name)
{
var_dump($name);
}
test('elePHPant');
test(null);
test();
こいつを実行すると以下の通りの挙動になります。
# php nullable.php
string(9) "elePHPant"
NULL
string(9) "elePHPant"
NULL
Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 0 passed in /var/dev/nullable.php on line 24 and exactly 1 expected in /var/dev/nullable.php:17
最後のエラーに関しては、nullは許すけど、引数に何も与えないとかは許さないって感じですね。
この辺は返り値にも当てはまるようです。
<?php
function testRet(): ?string
{
return null;
}
function testRet2(): ?string
{
}
var_dump(testRet());
var_dump(testRet2());
に対して、
# php nullable2.php
NULL
Fatal error: Uncaught TypeError: Return value of testRet2() must be of the type string or null, none returned in /var/dev/nullable2.php:11
void関数
前述のように、返却値を返すか、返却値すら返さないかは大きな違いになります。
返却値を全く返さない場合は、そういう関数であることを指定する別の方があり、それがvoidです。
<?php
function test(): void
{
echo '1';
}
function test2(): void
{
echo '2';
return;
}
function test3(): void
{
echo '3';
return null;
}
var_dump(test());
var_dump(test2());
var_dump(test3());
これを動作させてみると、
# php void.php
Fatal error: A void function must not return a value (did you mean "return;" instead of "return null;"?) in /var/dev/void.php on line 17
関数を読み込んだ時点で、エラーが出ます。
返却値はnullですら許しません。
一方でtest3の部分を削除して動作させると以下のようになります。
# php void.php
1NULL
2NULL
返却値がないので、var_dumpの値はnullを示しています。
Symmetric array destructuring
話は変わって、多重代入ですね。
今までlist
で書いていた多重代入が配列表記でできます。「list」って打たなくて良くなりました。
関数で複数のパラメータを返却したいとかに使うのですが、ちょっとだけ楽にかけそうです。
<?php
$data = [
[1, 'niisan'],
[2, 'harukao'],
];
function retList()
{
return [3, 'remore'];
}
// list() 形式
list($id1, $name1) = $data[0];
echo "$id1: $name1\n";
list($id2, $name2) = retList();
echo "$id2: $name2\n";
foreach ($data as list($id, $name)) {
echo "$id: $name\n";
}
echo "////////////////\n";
// [] 形式
[$id1, $name1] = $data[0];
echo "$id1: $name1\n";
[$id2, $name2] = retList();
echo "$id2: $name2\n";
foreach ($data as [$id, $name]) {
echo "$id: $name\n";
}
実行するとこんな感じになります。
# php list.php
1: niisan
3: remore
1: niisan
2: harukao
////////////////
1: niisan
3: remore
1: niisan
2: harukao
定数のアクセス範囲の指定
クラスなどで定数のアクセス範囲を設定できるようになりました。内部的に使っているのみで、外からは参照できない定数を作るのに便利です。
<?php
class ConstDemo
{
const PUBLIC_CONST_A = 1;
public const PUBLIC_CONST_B = 2;
protected const PROTECTED_CONST = 3;
private const PRIVATE_CONST = 4;
}
echo ConstDemo::PUBLIC_CONST_A . "\n";
echo ConstDemo::PUBLIC_CONST_B . "\n";
echo ConstDemo::PROTECTED_CONST . "\n";
これを実行すると以下のようになります。
# php const.php
1
2
Fatal error: Uncaught Error: Cannot access protected const ConstDemo::PROTECTED_CONST in /var/dev/constAccessor.php:12
Stack trace:
# 0 {main}
thrown in /var/dev/const.php on line 12
アクセス範囲がpublicでない定数にアクセスしようとしてFatalエラーが出ています。
iterable型
イテレータとして使える変数の擬似型としてiterableが追加されました。
iterable型はforeachで次々値を取り出せる変数なので、foreachが含まれる関数に数値とか渡されて、変なnoticeが出なくて良くなりますね。
<?php
function iterableFunc(iterable $trav)
{
foreach ($trav as $val) {
echo "$val";
}
echo "\n";
}
// generator
function gen() {
for ($i = 0; $i < 10; $i++) {
yield $i;
}
};
iterableFunc(['pen', 'pine', 'apple', 'pen']);
$gen = gen();
iterableFunc($gen);
iterableFunc('noiterable');
実行時の動作は以下のとおりです。
# php iterable.php
penpineapplepen
0123456789
Fatal error: Uncaught TypeError: Argument 1 passed to iterableFunc() must be iterable, string given, called in /var/dev/iterable.php on line 21 and defined in /var/dev/iterable.php:3
Stack trace:
# 0 /var/dev/iterable.php(21): iterableFunc('noiterable')
# 1 {main}
thrown in /var/dev/iterable.php on line 3
これは関数のタイプヒントでの例ですが、返却値に対しても指定できます。
<?php
function retIterable($switch = true): iterable
{
if ($switch) {
return [1, 2, 3];
}
return 123;
}
var_dump(retIterable());
var_dump(retIterable(false));
結果は以下のとおりです。
# php iterable2.php
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
Fatal error: Uncaught TypeError: Return value of retIterable() must be iterable, integer returned in /var/dev/iterable2.php:9
Stack trace:
# 0 /var/dev/iterable2.php(13): retIterable(false)
# 1 {main}
thrown in /var/dev/iterable2.php on line 9
関数やメソッドをクロージャー化する
関数やメソッドをクロージャーにすることができます。
strategyパターンとかで使えるかもしれません。
<?php
class Logics
{
public function getMethod($key)
{
return Closure::fromCallable([$this, $key]);
}
private function ichi(string $str) {return $str;}
private function ni(string $str) {return $str . $str;}
private function san(string $str) {return $str . $str . $str;}
}
$arr = ['ichi' => 'AAA', 'ni' => 'BBB', 'san' => 'CCC'];
$logics = new Logics;
foreach ($arr as $key => $str) {
$logic = $logics->getMethod($key);
var_dump($logic($str));
}
実行すると以下のようになります。
# php closure.php
string(3) "AAA"
string(6) "BBBBBB"
string(9) "CCCCCCCCC"
まとめ
他にも機能はあるのですが、あまり使わなそうなので、今回はここまでにしておきます。
なんだかモリモリPHPが発展しているような気がして個人的にとてもうれしいです。
今回は以上です。
参考
http://php.net/manual/ja/migration71.new-features.php
PHP7.1.0の新機能
PHP7.1のDocker