1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHPで可変関数を初めてちゃんと使った

Last updated at Posted at 2025-02-18

可変関数を初めてちゃんと使ったので、記録。

概要

PHPには「可変関数」という概念がある。
https://www.php.net/manual/ja/functions.variable-functions.php

PHP は可変関数(variable functions)の概念をサポートします。 これにより、変数名の後に括弧が付いている場合、その値が何であろうと PHPは、同名の関数を探し実行を試みます。 この機能は、コールバック、関数テーブル等を実装するために使用可能です。

とのこと。

共通部品に関数名の文字列を渡し、共通部品側では外部から受け取った変数名で関数を実行!なんてことができる。

同じクラス内で使う場合

関数名の文字列を変数として受け取り、その変数を用いて実行することができる。

class MyClass {
  public function execute($functionName) {
    $this->$functionName();
  }

  private function method1() {
    $this->execute('method2');
  }

  private function method2() {
    // 処理
  }
}

異なるクラス同士で使う場合

外部クラスに存在する関数を実行する場合は、関数名単体の文字列指定では使えない。
完全修飾名(例:MyClass::myMethod)で指定するか、クロージャーを使う必要がある。

完全修飾名で関数名を受け渡しする

public static メソッド名の文字列を受け取り、call_user_func(メソッド名の文字列, 引数) で実行する。

呼び出される側(関数を定義しているクラス)

public function handle($data) {
    $xxxClass = new xxxClass();
    $xxxClass->execute(
        $data,
        'App\Http\Controllers\XXXController::myMethod' // public staticメソッド
    );
}

呼び出し側

class xxxClass
{
    public function execute($data, $method) {
        $result = call_user_func($method, $data);
        // 処理
    }
}

クロージャーを使う

関数をクロージャーとして渡すこともできる。

呼び出される側(関数を定義しているクラス)

public function handle($data) {
    $xxxClass = new xxxClass();
    $xxxClass->execute(
        $data,
        function ($params) { // クロージャーで formatData を渡す
            return $this->formatData($params);
        }
    );
}

private function formatData($params)
{
    // コントローラー独自の処理
}

呼び出し側

class xxxClass
{
    public function execute($data, $method) {
        $result = $method($data);
        // 処理
    }
}

なお、無名関数で渡すこともできる。

$xxxClass->execute(
    $data,
    function ($params) {
        // 処理
    }
);

使ってみた

事例:取得したUserデータを1,000件ずつchunkしてCSVに書き込みたい。
書き込み処理は他の機能でも使えるようにUseCaseに切り出したい。
行フォーマットは該当のコントローラでしか利用しないので、privateメソッドにしておきたい。

Controller

public function handle() {
    // ファイルパスなどを準備
    $useCase = new xxxUseCase();
    $useCase->execute(
        User::query(),
        $filePath,
        function ($model) {
            return $this->rowFormatter($model);
        }
    );
    
    // 作成したCSVをダウンロード
}

private function rowFormatter(User $user): array
{
    return [
        $user->id,
        $user->name,
        $user->email,
        // 他の加工処理など
    ];
}

UseCase

function execute($query, $filePath, $rowFormatter) {
    $fp = fopen($filePath, 'a');
    $query->chunk(1000, function ($models) use ($fp, $rowFormatter) {
        foreach ($models as $model) {
            $row = $rowFormatter($model); // 関数を呼び出す
            $this->writeRow($fp, $row);
        }
    });
    fclose($fp);
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?