teratail header banner
teratail header banner
質問するログイン新規登録

質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

意見交換

6回答

480閲覧

use を使い引数を減らすか、使わずに引数を明示するか?

munekun

総合スコア117

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2025/06/20 14:26

編集2025/06/20 14:29

0

0

テーマ、知りたいこと

適切な理解ではなさそうですが、どうやら use を使うと引数が減らせるみたいで、使うべきかどうか悩んでいます。

背景・状況

比べたいのは下記2つの実行パターンです。

どうやら ➀ use を使って実行 の方だと executeWithLock() に渡す引数が1つ少なくて済む (第四引数が不要らしい) のです。
でも ChatGPT いわく、➁ use を使わず実行 のように第四引数に明示する方が近年の開発現場では推奨されるとかなんかでした。

経験が浅いのでどうすべきなのか迷っている状況です。

どういうときにどちらを使うと良いのが、ご意見頂けますと幸いです。

実行パターン

➀ use を使って実行

php

1class TagCompositeMapper 2{ 3 final public function createWithLock(TagComposite $tagComposite): TagComposite 4 { 5 $lockName = '$tagCompositeから適切なロック名を作る'; 6 $lockTimeout = 1; 7 8 $callBack = function () use ($tagComposite) { // -> 🔴use を使う 9 return $this->create($tagComposite); 10 }; 11 12 return (new LockUtil(new LockManager()))->executeWithLock( 13 $lockName, 14 $callback, 15 $lockTimeout, 16 // $tagComposite // -> 🔴use を使うとこの引数が不要 17 ); 18 } 19}
➁ use を使わず実行

php

1class TagCompositeMapper 2{ 3 final public function createWithLock(TagComposite $tagComposite): TagComposite 4 { 5 $lockName = '$tagCompositeから適切なロック名を作る'; 6 $lockTimeout = 1; 7 8 $callback = function (TagComposite $tagComposite) { // -> 🔵use を使わない 9 return $this->create($tagComposite); 10 }; 11 12 return (new LockUtil(new LockManager()))->executeWithLock( 13 $lockName, 14 $callback, 15 $lockTimeout, 16 $tagComposite // -> 🔵use を使わないとこの引数が必要 17 ); 18 } 19}

汎用部分のコード

上記で use を使うか使わないかで下記のように汎用部分のコードに違いが出ます。
これは小さな違いなのでどっちでも良さそうな感じはします。

php

1class LockUtil 2{ 3 private LockManager $lockManager; 4 5 public function __construct(LockManager $lockManager) 6 { 7 $this->lockManager = $lockManager; 8 } 9 10 final public function executeWithLock( 11 string $lockName, 12 callable $callback, 13 int $lockTimeout = 10, 14 ...$args // -> 🔵use を使わないときだけこれが必要 15 ) { 16 // ロック中 (ニアミスで他者が実行中) なら $lockTimeout まで待ってから throw される 17 if (!$this->lockManager->acquireLock($lockName, $lockTimeout)) { 18 throw new \RangeException(__METHOD__ . ": Failed to acquire lock: {$lockName}"); 19 } 20 21 try { 22 return $callback(); // -> 🔴use を使うときはこう 23 return $callback(...$args); // -> 🔵use を使わないときはこう 24 } finally { 25 $this->lockManager->releaseLock($lockName); 26 } 27 } 28}

以上です。
これまで use をほぼ使ったことがないためなんかヘンなことを言っているかもしれませんが、よろしくお願い致します。

バージョン

php 8.2 を利用していますが、もし「8.4 ならこうできる」などあればぜひ併せてご意見募集です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

回答7

#1

maisumakun

総合スコア146656

投稿2025/06/20 23:37

まずは、クロージャという単語について調べてみてください。

useで書いたものは、書いた時点での値が関数と紐づくことになります(useで参照を使うと、その後の変数の変化を追随することも可能です)。一方で、引数として渡す場合には、渡した時点の値が使われます。

今回のように、「その場で引数を渡せる」形に改変できるパターンはむしろ珍しい部類に属しますので、引数を増やす減らすの問題ではなく、必要な値を渡せる形はどちらかを、まず考えないといけません。


これは小さな違いなのでどっちでも良さそうな感じはします。

いえ、むしろここがクロージャにするかしないかでの本質的な違いが現れている部分です。逆に、コールバックに渡す引数を増やせない場合には、クロージャとして束縛する以外の手段はなくなります。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#2

munekun

総合スコア117

投稿2025/06/22 04:53

#1

maisumakun さん、ありがとうございます。

まずは、クロージャという単語について調べてみてください。

ふむふむ。まずクロージャ外のスコープの変数を、クロージャ内で使うための呪文が use だ。という感じですね。

コールバックに渡す引数を増やせない場合には、クロージャとして束縛する以外の手段はなくなります。

なるほど。基本的には下記 array_map() のように 引数を外から追加で渡せない ケースがほとんどで、これは use を使わざるをえない (=クロージャとして束縛するしかない) 。ということですね。

php

1array_map(function ($item) use ($rate) { 2 return $item * $rate; 3}, $prices);

今回のように、「その場で引数を渡せる」形に改変できるパターンはむしろ珍しい部類に属します

なるほど。今回のように 第四引数として渡せる ケースは珍しい部類なのですね。

引数を増やす減らすの問題ではなく、必要な値を渡せる形はどちらかを、まず考えないといけません。

え?でも use を使っても使わなくても、どちらでも executeWithLock()$tagComposite を渡せて、だからこそどちらが良いのかと悩んでいるのですが・・

maisumakun さんのご見解ですから、かなり本質的で端的な内容だろうという信頼があるので頑張って読んでみたのですが、すみません、理解が及びませんでした。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#3

yambejp

総合スコア117878

投稿2025/06/23 09:17

useを利用すると外部からの変数をカプセル化するときには便利ですがむしろ煩雑なのでクロージャーのデータの持ち込み以外あまり活用するケースは多くないと思います。

どうやら use を使うと引数が減らせるみたい

引数を減らすことだけに注力するならグローバル変数で処理すればよいですが、スコープの概念を捨てるということはある意味最悪ですね

PHP

1$GLOBALS["a"]=[1,2,3]; 2(function(){ 3 print_r($GLOBALS["a"]); 4})(); 5 6$b=[1,2,3]; 7(function(){ 8 global $b; 9 print_r($b); 10})();

折衷案としては引数は一旦配列におしこんで、関数の中で展開するという方法ですがこれもあまりスマートとは言い難いです

php

1$c=[1,2,3]; 2(function($args){ 3 print_r($args); 4})($c); 5 6$d=[1,2,3]; 7(function(){ 8 $args=func_get_args(); 9 print_r($args); 10})(...$d);

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#4

nanashi123

総合スコア128

投稿2025/06/23 09:55

useを使わないと追加の引数が必要というよりは、useを使うと引数を用意する意味がなくなると言った方が正確でしょうか
クロージャは、外部の変数をキャプチャする関数です
キャプチャのためにuseが必要なことは先に示されている通りですが、クロージャを使うということは、関数の結果がクロージャで補足された変数の状態に依存することを意味します

関数は本来、引数という形で初期値を外部から受け取ります
クロージャを作らない場合、内部関数は通常の関数と同様引数を要求するので、初期値となるパラメータを渡す必要が生じます
対してクロージャを用意した場合、その関数はキャプチャ変数を参照するので、引数が不要になります

ただクロージャを使う場合、キャプチャ変数の状態が関数の動作に関わってくるので、結果が一意には定まらない可能性があります
原則として、変数の状態が不変であることを保障できない限りは、ChatGPTの回答する通り、クロージャを使うべきではありません
例えばクロージャの実装直前に新規の変数へキャプチャ予定の変数を代入したりすると、それがインスタンス変数であった場合に非常にリスキーな状況となります
何故ならインスタンスの状態を共有するため、キャプチャされた変数とされない変数の双方で状態の観測及び変更が可能です
こうなると、関数外の変数が関数内の演算に干渉できるようになり、実行時エラーの究明に大きな支障をきたします

ライブラリ関数がクロージャをどう使うかはブラックボックスなので、必要に迫られない限りは通常の関数で間に合わせるべきです
ご提示のコードでもクロージャが通常のクラスを返すので、例えばこのインスタンスにキャプチャ変数の参照するインスタンスがメンバ値として含まれている可能性も否めません

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#5

munekun

総合スコア117

投稿2025/06/23 10:33

#3

yambejp さん、ありがとうございます。

たしかに、引数の数が最優先ならグローバル変数でも使っておきなさいとなってしまいそうですね。

func_get_args()、これはなんとなく見たことがありました。スマートさを判断できるだけの能力はありませんけれど、こういう使い方もできるのだと勉強になりました。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#6

munekun

総合スコア117

投稿2025/06/23 10:39

#4

nanashi123 さん、ありがとうございます。

"キャプチャ" という考え方がとても理解を助けれくれました。
その上で、どうなっていて何が困るのかと詳細なご説明を頂けましたので、納得感があります。

うーんなるほど・・これは苦労して初めてわかりそうな知見です。
大変参考になりました。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

#7

この回答は、運営により削除されました。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

この意見交換はまだ受付中です。

会員登録して回答してみよう

アカウントをお持ちの方は

関連した質問