これは2017年6月10日のPHPカンファレンス福岡2017懇親会LTで発表したものです。初出は2017年5月19日に社内勉強会で発表したものを大幅に加筆したものです。
これを5分…? 無理ですな。
お前誰よ
- うさみけんた / GitHub: zonuexe
-
ピクシブ株式会社 (東京)
- 福岡オフィスできました!
- CTOが赴任して週明けから稼動するよ
- PhpStorm普及業の傍らEmacsのphp-mode開発
このスライドはQiitaで公開済みなので、PHPについて知りたい型はゆっくり読んでね
せっかくなので自薦のPHP記事を置いておきますね
- FizzBuzzから始めるコードの再利用性を高めるトレーニング
- インスパイヤされて掲示板を作りたくなった(1)
- シンプルなルーティングがしたかった
- array_mapと部分適用→array_mapにありがとう、さよなら
- モダンPHPアンチパターン
さて
PHPの世界観
PHPの世界観
- 関数
- 言語構造(構文)
PHPの世界観
- 関数
- PHPの世界から定義できる
- 言語構造(構文)
- (PHPの世界からは)定義できない
- (C拡張で介入できるけど今回は触れない)
よくある質問
- Q.
isset
とis_null()
ってどう違うの? - Q.
isset
とarray_key_exists()
ってどう違うの?
よくある質問
- Q.
isset
とis_null()
ってどう違うの? - Q.
isset
とarray_key_exists()
ってどう違うの?
A. 違うよ、全然違うよ
関数
- 算数で習ったのは $f(x)=x\times2$ みたいなの
- PHP的には
$f = function($x) { return $x * 2; };
- ↑引数が同じなら絶対に同じ値を
return
する
- ↑引数が同じなら絶対に同じ値を
関数
- 算数で習ったのは $f(x)=x\times2$ みたいなの
- PHP的には
$f = function($x) { return $x * 2; };
- ↑引数が同じなら絶対に同じ値を
return
する
- ↑引数が同じなら絶対に同じ値を
余談
- PHP(とか他言語)の関数は、そうとは限らない
-
例)
mt_rand(0, 9)
は、その前提だと困る
関数のなかまたち (callable)
- ユーザー定義関数 (文):
function f($a){ ... }
- クロージャ (関数式):
$f = function($a) { ... };
- メソッド:
- クラス内
public function f($a){ ... }
- クラス内
- 静的メソッド:
- クラス内
public static function f($a){ ... }
- クラス内
- オブジェクト +
__invoke
(マジックメソッド)- クラス内
public function __invoke($a){ ... }
- クラス内
関数のなかまたち (callable)
- メソッドとかクロージャとかいろいろあるけど、こいつらは関数のようなもの
$f = [$obj, 'hoge']; // $obj->hoge()
$f = ['Ns\Klass', 'foo']; // Ns\Klass::foo()
$f($v);
is_callable($f); // => true
こんなこともできる
// Before
if ($v === 1) {
$obj->hoge($v)
} else {
Ns\Klass::foo($v)
}
// After
$f = ($v === 1) ? [$obj, 'hoge'] : ['Ns\Klass', 'foo'];
$f($v);
※ どちらが良いコードかは場面による
こんなこともできる
$ary = ["apple", "orange", "banana"];
// Before
$bry = [];
foreach ($ary as $i => $a) {
$bry[$i] => ucfirst($a);
}
// After
$cry = array_map('ucfirst', $ary);
// => ["Apple", "Orange", "Banana"]
ここまでは「関数」と「関数っぽいフレンズ(callable)」の話
「関数っぽいけど関数ではない」ものがある
言語構造(構文)
- 英語では
language constructs
-
if ($a == $b)
みたいなやつ- PHPの経験があれば
if
が関数ではない
({}
がくっついたりする)ことは明らかだが、言語仕様の知識がなければ、これは自明なことではない
- PHPの経験があれば
- 実際、
if
が言語構造(構文)ではない言語はある- みんな大好きなExcelとかね!
- PHPでif - Qiita
関数っぽく見える言語構造
諸説あるが
array
, assert
, declare
, die
, echo
, empty
, eval
, exit
, include
, include_once
, isset
, list
, print
, require
, require_once
, unset
, ……
一見すると見分けがつかない (主観)
WEB+DB PRESS Vol.94に掲載した「PHP大規模開発入門 【第15回】PHP初心者がハマりがちな落とし穴 ……型のキャスト,変数とリファレンス,引数による挙動の違い」に掲載したものを改変した。
構文 | 意味 | 例 |
---|---|---|
array | 配列リテラル | array(1, 2) |
assert | 表明 | assert(foo() === "foo") |
declare | PHP処理系に特殊な命令 | declare(strict_types=1) |
die | PHPスクリプトの終了 | foo() or dir(1); |
echo | 文字列を標準出力 | echo $message, PHP_EOL; |
empty | 値/変数が「空」または「偽」かの検査 | if (empty($v) || empty($a['i'])) |
eval | 文字列をPHPスクリプトとして評価 | eval($s) |
exit | PHPスクリプトの終了 | exit(0); |
include include_once |
PHPスクリプトの読み込み | include_once __DIR__ . '/Foo.php'; |
isset | 値/変数が存在するかの検査 | $v = isset($a['i']) ? $a['i'] : 's'; |
list | 複数の値(配列)を変数に代入 | list($a, $b, $c) = [1, 2, 3]; |
文字列を標準出力 | ($c === 1) ? print $t : print $f; |
|
require require_once |
PHPスクリプトの読み込み | require 'lib.php'; |
unset | 変数/インデックスの破棄 |
unset($v); unset($a['i']);
|
いっぱいある!!!!
出力するやつ
echo, print
echo "fizz";
echo("buzz");
print "foo";
print("bar");
echo, print
- デフォルトで標準出力に出力できる
-
echo
は値を返さない -
print
は値を返す (関数っぽい言語構造) - 出力バッファリングでキャプチャできる
-
fwrite(STDOUT, ...)
とは微妙に異なる ←重要
echo, print
// これはok
$v === "x" and print "foo";
// これはだめ
$v === "x" and echo "foo";
// PHP Parse error: Syntax error, unexpected T_ECHO on line 1
PHPを終了するやつ
exit, die
exit;
exit(1);
foo() or die(1);
exit, die
- 引数で渡した値は終了ステータスになる
- 0が正常、1が異常
- Webサーバーだと200とか500とかにマッピングされる
配列リテラル
$a = array()
$b = array("apple", "banana", "orange");
$c = array("name" => "Miku", "age" => 16);
list($a, $b) = foo();
list($a) = array("a");
// PHP 7.1から
list("foo" => $f) = ["foo" => "F"];
- PHP 5.3までは
["apple", "banana", "orange"]
って書けなかった -
list()
は関数っぽいものが代入の左辺にあって他の言語の常識があると死ぬ
ディレクティブ宣言
declare
<?php
declare(strict_types=1);
declare(ticks=1);
declare(encoding='ISO-8859-1');
- ファイルローカルに適用される特殊な宣言
- 関数っぽいけど
declare(name=val)
みたいな変な構文 - ファイルのコンパイル時に評価される
- 変数・定数などは利用できない
値のチェック
isset, empty
isset($v);
isset($v[0]);
isset($v, $w);
empty($v);
empty($v[0]);
-
isset
は複数の値を評価できる -
empty
はPHP 5.5までは変数しか評価できなかった
ファイルを読み込む
include, require
include("foo.php");
require("foo.php");
include_once("foo.php");
require_once("foo.php");
-
()
は省略可能 - 絶対パスではないファイル指定をすると、
include_path
から探索する- なので最近はオートローディングが主流
- PHPをテンプレートエンジンとして利用するときは部分テンプレートを取り込める
コード辺を実行したりする
eval("foo();");
eval("\$v = foo();");
変数を消す
unset($v);
unset($v["key"]);
表明
assert
assert(foo() === 1);
assert("foo() === 1");
- PHP 5では関数
- PHP 7では関数でもあり言語構造でもある
謎の存在に昇華したis_callable('assert') // => true
- おそらく互換性のため
- 本番運用時に実行されないようにしたりできる
最後に
言語構造ではないもの(ただの関数)
// C言語の sizeof は演算子
// PHPでは、ただの関数 (countのエイリアス)
$i = sizeof($a);
$i = sizeof $a; // ← これはだめ!