Knowledge Base

お知らせや身辺のことを綴っています。

PHP の勉強

list() を使って複数の戻り値を効率的に受け取る

Array 型の戻り値を返してくる関数から戻り値を効率的に受け取りたいときは、list() を利用する。PHP 7.1.0 以降は、[] という配列を示す表記を使うこともできる。

<?php 
function get_greet_message(string $object = 'world!'): array {
    $greeting = ['Hello', $object];
    return $greeting;
}

list($a, $b) = get_greet_message();
print("{$a} {$b}\n");
// Hello world!

// PHP 7.1.0 以降はこのような書き方も可能
[$a, $b] = get_greet_message('Yokkin!');
print("{$a} {$b}\n");
// Hello Yokkin!

クラス内メソッドの実行

() で括れば勝手に式と評価してくれるので、うまくやればインスタンス変数を作成せずにクラス内のメソッドを実行することができる

<?php
// インスタンス変数を作成せずにクラス内のメソッドを実行
(new Filter())->run();

class Filter {
    protected $var = 'Hello world!';

    public function run() : void {
        print $this->var;
    }
}

// Hello world!

PHP で関数型プログラミング

関数型プログラミングのパラダイムを学んだことで、array_map() とか array_reduce(), array_walk(), のような PHP 組み込みの高階関数を使うのが楽しくなってきたので、少し練習してみる。

array_map() の練習

以下は、配列にある県名のアイテムに「県」を付与してマッピングするプログラム。array_map()$this->prefectures にある配列の数だけ callback をそれに対して実行してくれるような関数である。

<?php
(new Prefecture())->run();

class Prefecture
{
    public $prefectures = ['千葉', '埼玉', '神奈川', '茨城', '長野'];
    
    public function run()
    {
        echo var_export($this->add_sufix()), "\n";
    }
    
    // コールバック関数を用意する例
    public function add_sufix(): array
    {
        function callback(string $pref): string
        {
            return "{$pref}県";
        }
        
        return (array_map('callback', $this->prefectures));
    }
}

アロー関数を使うとさらにコンパクトに処理を記述できる。ただし、アロー関数は1つの式 (Expression) しか格納できないので、2行以上書きたかったら普通の匿名関数を利用するべきであることに留意する。

public function add_sufix(): array
{
    return (array_map(fn($pref): string => "{$pref}県", $this->prefectures));
}

出力結果は以下のようになる。

array (
  0 => '千葉県',
  1 => '埼玉県',
  2 => '神奈川県',
  3 => '茨城県',
  4 => '長野県',
)

Closure: use($variable)

PHP でクロージャを利用する際、関数のスコープは親元のスコープと同じであるが、別途宣言をする必要がある。もし、親元の変数を関数内に持ち越したいときは、クロージャの後ろに use ($var) と書いて、使用する変数を宣言することでクロージャ内に親元の文脈で宣言した変数をそのまま持ってこれるようになる。なお、型アノテーションを利用する際は、宣言の後ろに書く。

<?php
$d = "C:\Program Files\php\8.1.11";
function getdir(string: $d): array
{
    return array_values(array_filter(array_map(
        function (string: $i) use ($d): string {
            return (is_dir($d . '/' . $i)) ? $i : '';
        },
        array_slice(scandir($d, 0), 2),
    )));
}

var_export(getdir($d));

アロー関数に限っては、ブロックを持たないので、 use を用いることなく変数はそのまま持ち越せる。見通しがとてもよくなる。

<?php
$d = "C:\Program Files\php\8.1.11";
function getdir(string: $d): array
{
    return array_values(array_filter(array_map(
        fn (string $i): string => (is_dir($d . '/' . $i)) ? $i : '',
        array_slice(scandir($d, 0), 2),
    )));
}

var_export(getdir($d));

出力結果

array (
  0 => 'dev',
  1 => 'ext',
  2 => 'extras',
  3 => 'lib',
)

名前付き引数を使う

PHPでは、関数がとる引数名を一種のキーワードとして指定することで、関数の呼び出し時に順番を気にせず引数を指定できる。いわゆる Python の キーワード引数みたいな方法で関数を呼び出すことができる。なお、位置が指定された引数と一緒に使うときは、その後ろに名前付き引数を置かなければいけない。

https://www.php.net/manual/ja/functions.arguments.php#functions.named-arguments

<?php
function add_https(string $domain_name, bool $is_ssl) : array
{
    $protocol = ($is_ssl) ? 'https://' : 'http://';
    return [$protocol, $domain_name];
}

/* 
 * ここでは、$is_ssl は is_ssl に、$domain_name は domain_name にそれぞれ対応する
 */

[$prefix, $domain] = add_https(is_ssl: true, domain_name: 'yokkin.com/');
echo $prefix, $domain;

// https://yokkin.com/