1
0
mirror of https://github.com/php/doc-ja.git synced 2026-04-29 11:03:19 +02:00
Files
archived-doc-ja/language/functions.xml
T
2025-08-27 22:14:38 +09:00

1795 lines
52 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: dd87866772c31671146ff778140dc0955c55005c Maintainer: takagi Status: ready -->
<!-- CREDITS: hirokawa,mumumu,jdkfx -->
<chapter xml:id="language.functions" xmlns="http://docbook.org/ns/docbook">
<title>関数</title>
<sect1 xml:id="functions.user-defined">
<title>ユーザー定義関数</title>
<para>
関数は、<literal>function</literal> キーワードと関数の名前、
カンマ(<literal>,</literal>) で区切ったパラメーターのリスト
(空であっても構いません)を括弧で囲み、
関数の本体を波括弧で囲んだものを続けて定義します。
たとえば、以下のようになります:
</para>
<example>
<title><literal>foo</literal> という名前の新しい関数を宣言する</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
echo "関数の例\n";
return $retval;
}
?>
]]>
</programlisting>
</example>
<note>
<para>
PHP 8.0.0 以降では、
パラメーターのリストの末尾に、カンマを付加できるようになっています:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
function foo($arg_1, $arg_2,) { }
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
<simpara>
関数の本体の中では、
他の関数や <link linkend="language.oop5.basic.class">クラス</link>
定義を含む PHP のあらゆる有効なコードを使用することができます。
</simpara>
<para>
関数名は、PHP の他のラベルと同じ規則に従います。関数名として有効な
形式は、まず文字かアンダースコアで始まり、その後に任意の数の文字・
数字・あるいはアンダースコアが続くものです。正規表現で表すと、
<code>^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$</code>
となります。
</para>
&tip.userlandnaming;
<simpara>
PHP では、関数は参照される前に定義されている必要はありません。
ただし以下の二つの例のように、条件付きで関数が
定義されるような場合を<emphasis>除きます</emphasis>
</simpara>
<para>
次の二つの例のように、ある条件下でのみ関数が定義される場合には、
その関数定義は関数がコールされる<emphasis>前に</emphasis>
行われていなければなりません。
</para>
<para>
<example>
<title>条件つきの関数</title>
<programlisting role="php">
<![CDATA[
<?php
$makefoo = true;
/* ここでは関数foo()はまだ定義されていないので
コールすることはできません。
しかし関数 bar()はコールできます。 */
bar();
if ($makefoo) {
function foo()
{
echo "I don't exist until program execution reaches me.\n";
}
}
/* ここでは $makefooがtrueと評価されているため
安全にfoo()をコールすることができます。 */
if ($makefoo) foo();
function bar()
{
echo "I exist immediately upon program start.\n";
}
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>関数の中の関数</title>
<programlisting role="php">
<![CDATA[
<?php
function foo()
{
function bar()
{
echo "I don't exist until foo() is called.\n";
}
}
/* ここでは関数bar()はまだ定義されていないので
コールすることはできません。 */
foo();
/* foo()の実行によって bar()が
定義されるためここではbar()を
コールすることができます。*/
bar();
?>
]]>
</programlisting>
</example>
</para>
<para>
PHP では、関数やクラスはすべてグローバルスコープにあります -
関数の内部で定義したものであっても関数の外部からコールできますし、
その逆も可能です。
</para>
<simpara>
PHP は関数のオーバーロードをサポートしていません。
また、宣言された関数の定義を取り消したり再定義することも
できません。
</simpara>
<note>
<simpara>
関数名は ASCII 文字 <literal>A</literal> から <literal>Z</literal> で構成されている場合、
大文字小文字を区別しませんが、
通常は関数宣言時と同じ名前で関数をコールする方が好ましいです。
</simpara>
</note>
<simpara>
<link linkend="functions.variable-arg-list">可変引数</link>
および <link linkend="functions.arguments.default">デフォルト引数</link>
の機能をサポートしています。
<function>func_num_args</function>,
<function>func_get_arg</function>,
<function>func_get_args</function> に関する関数リファレンスを
参照ください。
</simpara>
<para>
PHP では、関数を再帰的にコールすることが可能です。
<example>
<title>再帰的な関数</title>
<programlisting role="php">
<![CDATA[
<?php
function recursion($a)
{
if ($a < 20) {
echo "$a\n";
recursion($a + 1);
}
}
?>
]]>
</programlisting>
</example>
<note>
<simpara>
100 から 200 を超えるようなレベルの再帰呼び出しは避けてください。そんなことをすると、
スタックが破壊され、スクリプトが異常終了してしまいます。
無限に続くような再帰処理は、プログラミングの間違いでしょう。
</simpara>
</note>
</para>
</sect1>
<sect1 xml:id="functions.arguments">
<title>関数のパラメーターと引数</title>
<simpara>
関数のパラメーターは、関数のシグネチャの中で宣言します。
引数のリストにより関数へ情報を渡すことができます。
このリストは、カンマで区切られた式のリストです。
引数の評価は、関数が実際にコールされる前に、
左から右の順番で行われ、
評価された結果が関数のパラメーターに代入されます
(<emphasis>先行</emphasis>評価)。
</simpara>
<!-- Note: this paragraph feels like it should be moved to the syntax part? -->
<para>
PHP は、値渡し(デフォルト)、
<link linkend="functions.arguments.by-reference">リファレンス渡し</link>
<link linkend="functions.arguments.default">デフォルト引数値</link>
をサポートしています。また、
<link linkend="functions.variable-arg-list">可変長引数リスト</link> や、
<link linkend="functions.named-arguments">名前付き引数</link>
もサポートしています。
</para>
<note>
<para>
PHP 7.3.0 以降では、
関数コールの引数リストの末尾にも、カンマを付加できるようになっています:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$v = foo(
$arg_1,
$arg_2,
);
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
<para>
PHP 8.0.0 以降では、関数のパラメーターリストの最後にカンマをつけることができます。
このカンマは無視されます。
これは、引数リストや変数名が長かったりした場合に、
引数を縦に並べるのに便利です。
</para>
<example>
<title>関数のパラメーターリストの最後にカンマを付ける</title>
<programlisting role="php">
<![CDATA[
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // この最後のカンマは、8.0.0 より前では許されません。
)
{
// ...
}
?>
]]>
</programlisting>
</example>
<sect2 xml:id="functions.arguments.by-reference">
<title>引数のリファレンス渡し</title>
<simpara>
デフォルトで、関数の引数は値で渡されます。(このため、関数の内部で
引数の値を変更しても関数の外側では値は変化しません。)関数がその引
数を修正できるようにするには、その引数をリファレンス渡しとする必要があり
ます。
</simpara>
<para>
関数の引数を常にリファレンス渡しとしたい場合には、関数定義において
アンパサンド(&amp;) をパラメーター名の前に付加することができます。
</para>
<para>
<example>
<title>関数の引数のリファレンス渡し</title>
<programlisting role="php">
<![CDATA[
<?php
function add_some_extra(&$string)
{
$string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str; // 出力は 'This is a string, and something extra.' となります
?>
]]>
</programlisting>
</example>
</para>
<para>
リファレンス渡しが想定されているところに、定数式を引数として渡すとエラーになります。
</para>
</sect2>
<sect2 xml:id="functions.arguments.default">
<title>デフォルトのパラメーター値</title>
<para>
関数は、変数に代入する記法に似たやり方で、
デフォルト値をパラメーターに定義することができます。
デフォルト値はパラメーターに引数が指定されなかった場合に使われますが、
&null; を渡した場合はデフォルト値を代入
<emphasis>しない</emphasis> ことに特に注意して下さい。
</para>
<para>
<example>
<title>関数におけるデフォルト引数の使用法</title>
<programlisting role="php">
<![CDATA[
<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.
]]>
</screen>
</example>
</para>
<para>
デフォルト引数の値には、スカラー値、
配列、および特殊な型 &null; を指定できます。
PHP 8.1.0 以降では、
<link linkend="language.oop5.basic.new">new ClassName()</link>
記法を使ってオブジェクトも指定できます。
</para>
<para>
<example>
<title>スカラー型以外をデフォルト値として使用する</title>
<programlisting role="php">
<![CDATA[
<?php
function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL)
{
$device = is_null($coffeeMaker) ? "hands" : $coffeeMaker;
return "Making a cup of ".join(", ", $types)." with $device.\n";
}
echo makecoffee();
echo makecoffee(array("cappuccino", "lavazza"), "teapot");?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>オブジェクトをデフォルト値として使用する(PHP 8.1.0 以降)</title>
<programlisting role="php">
<![CDATA[
<?php
class DefaultCoffeeMaker {
public function brew() {
return 'Making coffee.';
}
}
class FancyCoffeeMaker {
public function brew() {
return 'Crafting a beautiful coffee just for you.';
}
}
function makecoffee($coffeeMaker = new DefaultCoffeeMaker)
{
return $coffeeMaker->brew();
}
echo makecoffee();
echo makecoffee(new FancyCoffeeMaker);
?>
]]>
</programlisting>
</example>
</para>
<simpara>
デフォルト値は、定数式である必要があり、
(例えば) 変数やクラスのメンバーであってはなりません。
</simpara>
<para>
デフォルト値を有する引数は、
デフォルト値がない引数の右側に全てある必要があることに注意して下さい。
そうでない場合、デフォルト値を指定していても、
呼び出し時に省略できません。
次の簡単なコードを見てみましょう。
</para>
<para>
<example>
<title>関数のパラメーターのデフォルト値の 間違った使用法</title>
<programlisting role="php">
<![CDATA[
<?php
function makeyogurt($container = "bowl", $flavour)
{
return "Making a $container of $flavour yogurt.\n";
}
echo makeyogurt("raspberry"); // $container に "raspberry" を指定します。$flavour ではありません。
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Fatal error: Uncaught ArgumentCountError: Too few arguments
to function makeyogurt(), 1 passed in example.php on line 42
]]>
</screen>
</example>
</para>
<para>
ここで、上の例を次のコードと比べてみましょう。
</para>
<para>
<example>
<title>関数のパラメーターのデフォルト値の 正しい使用法</title>
<programlisting role="php">
<![CDATA[
<?php
function makeyogurt($flavour, $container = "bowl")
{
return "Making a $container of $flavour yogurt.\n";
}
echo makeyogurt("raspberry"); // $flavour に "raspberry" を指定します。
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Making a bowl of raspberry yogurt.
]]>
</screen>
</example>
</para>
<para>
PHP 8.0.0 以降では、
デフォルト値を指定した引数を複数スキップするために、
<link linkend="functions.named-arguments">名前付き引数</link>
が使えます。
</para>
<para>
<example>
<title>関数の引数のデフォルト値の 正しい使用法</title>
<programlisting role="php">
<![CDATA[
<?php
function makeyogurt($container = "bowl", $flavour = "raspberry", $style = "Greek")
{
return "Making a $container of $flavour $style yogurt.\n";
}
echo makeyogurt(style: "natural");
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Making a bowl of raspberry natural yogurt.
]]>
</screen>
</example>
</para>
<para>
PHP 8.0.0 以降では、
デフォルト値を指定したパラメーターの後に、
必須のパラメーターを宣言することは <emphasis>推奨されません</emphasis>
なぜなら、そのデフォルト値は絶対に使われないからです。
これは、デフォルト値を削除することで解決できます。
このルールの唯一の例外は、
<code>Type $param = null</code> と書かれたパラメーターです。
&null; をデフォルトにすることは、
型が暗黙のうちに nullable であることを示しています。
この使い方はPHP 8.4.0で非推奨となり、代わりに明示的な
<link linkend="language.types.declarations.nullable">nullable 型</link>
を使用する必要があります。
<example>
<title>デフォルト値を指定したパラメーターは、必須のパラメーターの後に宣言する</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($a = [], $b) {} // デフォルト値が使われないため、PHP 8.0.0 以降は推奨されません
function foo($a, $b) {} // 上のコードと機能的には同じですが、推奨されない警告は発生しません。
// PHP 8.1.0以降、$a は暗黙的に必須(必須の引数の前にあるため)ですが、
// デフォルトのパラメータ値が null であるため、暗黙的に nullable とみなされます(PHP 8.4.0で非推奨)。
function bar(A $a = null, $b) {}
function bar(?A $a, $b) {} // 推奨される書き方です。
?>
]]>
</programlisting>
</example>
</para>
<note>
<simpara>
PHP 7.1.0 以降では、
デフォルト値を指定しないで引数を省略すると、
<classname>ArgumentCountError</classname>
がスローされるようになりました。
これより前のバージョンでは、警告が発生していました。
</simpara>
</note>
<note>
<simpara>
リファレンス渡しのパラメーターにもデフォルト値を指定できます。
</simpara>
</note>
</sect2>
<sect2 xml:id="functions.variable-arg-list">
<title>可変長引数リスト</title>
<simpara>
PHP は <literal>...</literal> を使った可変長引数をユーザー定義関数でサポートしています。
</simpara>
<para>
パラメーターリストに
<literal>...</literal> トークンを含めることで、
その関数が可変長の引数を受け取ることを示せます。
引数は、指定した変数に配列として渡されます:
<example>
<title><literal>...</literal> を使った、可変長引数へのアクセス</title>
<programlisting role="php">
<![CDATA[
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
10
]]>
</screen>
</example>
</para>
<para>
関数を呼び出すときに <literal>...</literal> を使うと、
配列や <classname>Traversable</classname> を実装した変数やリテラルを引数リストに展開することができます。
<example>
<title>引数での <literal>...</literal> の使用例</title>
<programlisting role="php">
<![CDATA[
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
3
3
]]>
</screen>
</example>
</para>
<para>
通常のパラメーターを、<literal>...</literal> の前に指定することもできます。
この場合は、通常の引数リストにマッチしなかったのこりの引数が
<literal>...</literal> による配列に追加されます。
</para>
<para>
<literal>...</literal> トークンの前に、
<link linkend="language.types.declarations">型宣言</link> を付加することもできます。
型宣言がある場合、<literal>...</literal> が取り込むすべての引数はその型に一致していなければいけません。
<example>
<title>型宣言つきの可変長引数</title>
<programlisting role="php">
<![CDATA[
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// これは失敗します。null は DateInterval オブジェクトではないからです。
echo total_intervals('d', null);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
]]>
</screen>
</example>
</para>
<para>
可変長引数の
<link linkend="functions.arguments.by-reference">リファレンス渡し</link>
もできます。その場合は、<literal>...</literal> の前にアンパサンド
(<literal>&amp;</literal>) を付加します。
</para>
</sect2>
<sect2 xml:id="functions.named-arguments">
<title>名前付き引数</title>
<para>
既にある、位置を指定した引数を拡張する形で、PHP 8.0.0 から名前付き引数が導入されました。
名前付き引数は、位置ではなく、名前ベースで引数を渡すことを可能にします。
これによって、引数の意味が自己文書化(self-documenting)され、
引数を任意の順番で渡せるようになり、任意のデフォルト値を持つ引数をスキップできるようになります。
</para>
<para>
名前付き引数は、引数の名前の後にコロンを付けたものを、値の前に付けることで指定します。
引数の名前に予約語を使うことも許されています。
引数の名前は識別子でなければならず、動的に指定することは出来ません。
</para>
<example>
<title>名前付き引数の文法</title>
<programlisting role="php">
<![CDATA[
<?php
myFunction(paramName: $value);
array_foobar(array: $value);
// 以下の書き方はサポートされていません
function_name($variableStoringParamName: $value);
?>
]]>
</programlisting>
</example>
<example>
<title>位置を指定した引数と、名前付き引数</title>
<programlisting role="php">
<![CDATA[
<?php
// 位置を指定した引数の場合:
array_fill(0, 100, 50);
// 名前付き引数の場合:
array_fill(start_index: 0, count: 100, value: 50);
?>
]]>
</programlisting>
</example>
<para>
名前付き引数は、渡す順番は関係ありません。
</para>
<example>
<title>上と同じ例を、引数の順番を変えて渡す</title>
<programlisting role="php">
<![CDATA[
<?php
array_fill(value: 50, count: 100, start_index: 0);
?>
]]>
</programlisting>
</example>
<para>
名前付き引数は、位置を指定した引数と組み合わせることが出来ます。
そうした場合、名前付き引数は、位置を指定した引数の後に置かなければいけません。
オプションの引数だけをいくつか、指定することもできます。
その場合も、名前付き引数の順番は関係ありません。
</para>
<example>
<title>位置を指定した引数と、名前付き引数を組み合わせる</title>
<programlisting role="php">
<![CDATA[
<?php
htmlspecialchars($string, double_encode: false);
// 上記は、以下と同等です。
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>
]]>
</programlisting>
</example>
<para>
同じ名前の引数を複数回渡すと、<classname>Error</classname> 例外が発生します。
</para>
<example>
<title>同じ名前の引数を複数回渡すと、Error がスローされる</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($param) { ... }
foo(param: 1, param: 2);
// Error: Named parameter $param overwrites previous argument
foo(1, param: 2);
// Error: Named parameter $param overwrites previous argument
?>
]]>
</programlisting>
</example>
<para>
PHP 8.1.0 以降では、
引数を ... で展開した後に 名前付き引数を指定することができます。
名前付き引数は、展開済みの引数を上書きしては <emphasis>いけません</emphasis>
</para>
<example>
<title>引数を展開した後に、名前付き引数を使う</title>
<programlisting role="php">
<![CDATA[
<?php
function foo($a, $b, $c = 3, $d = 4) {
return $a + $b + $c + $d;
}
var_dump(foo(...[1, 2], d: 40)); // 46
var_dump(foo(...['b' => 2, 'a' => 1], d: 40)); // 46
var_dump(foo(...[1, 2], b: 20)); // Fatal error. Named parameter $b overwrites previous argument
?>
]]>
</programlisting>
</example>
</sect2>
</sect1>
<sect1 xml:id="functions.returning-values">
<title>戻り値</title>
<para>
オプションの return 文により値を返すことができます。
配列やオブジェクトを含むあらゆる型を返すことができます。
これにより、関数の実行を任意の箇所で終了し、その関数を呼び出した
箇所に制御を戻すことが出来ます。詳細に関しては
<function>return</function> を参照ください。
</para>
<note>
<para>
<function>return</function> を省略した場合は &null; を返します。
</para>
</note>
<sect2>
<title>return の使いかた</title>
<para>
<example>
<title><function>return</function> の使用法</title>
<programlisting role="php">
<![CDATA[
<?php
function square($num)
{
return $num * $num;
}
echo square(4); // '16'を出力
?>
]]>
</programlisting>
</example>
</para>
<para>
関数は複数の値を返すことは出来ませんが、
配列を返すことで似たような結果を得ることができます。
</para>
<para>
<example>
<title>複数の値を得るために配列を返す例</title>
<programlisting role="php">
<![CDATA[
<?php
function small_numbers()
{
return [0, 1, 2];
}
// 配列を展開させると、配列のそれぞれのメンバが個別に得られます。
[$zero, $one, $two] = small_numbers();
// PHP 7.1.0 より前のバージョンで上と同じことをするには、
// 言語構造 list を使うしかありません。
list($zero, $one, $two) = small_numbers();
?>
]]>
</programlisting>
</example>
</para>
<para>
関数からリファレンスを返すためには、
関数宣言と戻り値を代入する変数に対して、
リファレンス演算子 &amp; を使います:
</para>
<para>
<example>
<title>関数からリファレンスを返す</title>
<programlisting role="php">
<![CDATA[
<?php
function &returns_reference()
{
return $someref;
}
$newref =& returns_reference();
?>
]]>
</programlisting>
</example>
</para>
<simpara>
リファレンスに関する詳細は、<link
linkend="language.references">リファレンスの説明</link> を参照ください。
</simpara>
</sect2>
</sect1>
<sect1 xml:id="functions.variable-functions">
<title>可変関数</title>
<para>
PHP は可変関数(variable functions)の概念をサポートします。
これにより、変数名の後に括弧が付いている場合、その値が何であろうと
PHPは、同名の関数を探し実行を試みます。
この機能は、コールバック、関数テーブル等を実装するために使用可能です。
</para>
<para>
可変関数は、<function>echo</function>, <function>print</function>,
<function>isset</function>, <function>empty</function>,
<function>include</function>,
<function>require</function>
のような言語構造と組み合わせて使用する
ことはできません。これらの言語構造を可変変数として使うには
独自のラッパー関数を使う必要があります。
</para>
<para>
<example>
<title>可変関数の例</title>
<programlisting role="php">
<![CDATA[
<?php
function foo()
{
echo "In foo()<br />\n";
}
function bar($arg = '')
{
echo "In bar(); argument was '$arg'.<br />\n";
}
// これは、echo のラッパー関数です。
function echoit($string)
{
echo $string;
}
$func = 'foo';
$func(); // This calls foo()
$func = 'bar';
$func('test'); // This calls bar()
$func = 'echoit';
$func('test'); // This calls echoit()
?>
]]>
</programlisting>
</example>
</para>
<para>
オブジェクトのメソッドを可変関数を使ってコールすることもできます。
<example>
<title>可変メソッドの例</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // Bar() メソッドのコール
}
function Bar()
{
echo "This is Bar";
}
}
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // $foo->Variable() をコールする
?>
]]>
</programlisting>
</example>
</para>
<para>
staticメソッドをコールするときには、関数呼び出しのほうがstaticプロパティ演算子よりも優先されます。
<example>
<title>staticプロパティを含む可変メソッドの例</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
static $variable = 'static property';
static function Variable()
{
echo 'Method Variable called';
}
}
echo Foo::$variable; // これは 'static property' を表示します。このスコープにおいて $variable が必要です。
$variable = "Variable";
Foo::$variable(); // これは $foo->Variable() をコールします。このスコープでの $variable の内容を読むからです。
?>
]]>
</programlisting>
</example>
</para>
<para>
<example>
<title>複雑な callable</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
static function bar()
{
echo "bar\n";
}
function baz()
{
echo "baz\n";
}
}
$func = array("Foo", "bar");
$func(); // "bar" を表示します
$func = array(new Foo, "baz");
$func(); // "baz" を表示します
$func = "Foo::bar";
$func(); // "bar" を表示します。
?>
]]>
</programlisting>
</example>
</para>
<sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>is_callable</function></member>
<member><function>call_user_func</function></member>
<member><function>function_exists</function></member>
<member><link linkend="language.variables.variable">可変変数</link></member>
</simplelist>
</para>
</sect2>
</sect1>
<sect1 xml:id="functions.internal">
<title>内部(ビルトイン)関数</title>
<para>
PHPは標準で多くの関数と言語構造を持っています。また他にも
コンパイル済みの特定のPHP拡張モジュールを必要とする関数があります。
それらはもしコンパイルされていなければ"undefined function(未定義の関数)"
として致命的エラーを発するでしょう。例えば、
<function>imagecreatetruecolor</function>のような
<link linkend="ref.image">画像</link>関数を使用するには、
<productname>GD</productname>サポートを有効にしてPHPをコンパイルしておく必要があります。
また、<function>mysqli_connect</function>を使う場合もやはり
<link linkend="ref.mysql">MySQL</link>サポートを有効にしてPHPが
コンパイルされている必要があります。
<link linkend="ref.strings">string</link>
<link linkend="ref.var">variable</link>関数のように
どのバージョンのPHPでも含まれているコアの関数もたくさんあります。
<function>phpinfo</function><function>get_loaded_extensions</function>
コールすることで使用しているPHPにロードされている拡張モジュールを
見ることができます。また、多くの拡張モジュールはデフォルトで有効に
なっており、PHPのマニュアルは拡張モジュール毎に分けられていることにも
注意してください。PHPのセットアップについては
<link linkend="configuration">設定</link>,
<link linkend="install">インストール</link>,そして個々の拡張モジュール
の項をご覧ください。
</para>
<para>
関数のプロトタイプに関する解説はマニュアルの
<link linkend="about.prototypes">関数の定義を読むには</link>
参照ください。関数の戻り値や引数が直接与えられた場合に
どのように動くかを認識することは重要です。
例えば、<function>str_replace</function>は変更された文字列を
返すのに対し、<function>usort</function>は与えられた引数そのものを
変更します。マニュアルの各項にはそれぞれの関数に関する情報があります。
関数の引数、振る舞いの変更、成功した場合失敗した場合の
それぞれの戻り値、可用性に関する情報などです。
これらの重要な(時には微妙な)違いを知ることは、
正しいPHPコードを書くうえで極めて重要なことです。
</para>
<note>
<simpara>
関数へのパラメータとして関数が想定しているのとは異なるものを渡した場合、
例えば文字列を想定しているところに配列を渡した場合などの場合は
関数の戻り値は未定義となります。たいていの場合は
&null; を返すでしょう。しかしこれはあくまでも規約にすぎず、
これに依存することはできません。
PHP 8.0.0 以降では、このような場合には <classname>TypeError</classname> をスローすることになっています。
</simpara>
</note>
<note>
<para>
ビルトイン関数のスカラー型の引数には、
デフォルトの自動変換(coercive)モードの場合、
null を渡すことが出来ます。
PHP 8.1.0 以降では、
nullable として宣言されていない内部関数の引数に &null; を渡すことは推奨されなくなり、
自動変換モードでは警告が発生するようになっています。
ユーザ定義の関数においては、スカラー型の引数は nullable と明示的にマークする必要があり、その振る舞いと合わせるためです。
</para>
<para>
たとえば、<function>strlen</function>
関数は引数 <literal>$string</literal>
に null でない文字列を渡すことを期待しています。
歴史的な理由により、
PHP は自動変換モードの場合に、
この引数に &null; を渡すことを許可してきました。
結果として、引数に &null;
を渡すと暗黙のうちに文字列にキャストされ、
結果は空文字列 <literal>""</literal> になっていました。
これに対し、strict モードの場合は <classname>TypeError</classname>
がスローされます。
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
var_dump(strlen(null));
// "Deprecated: Passing null to parameter #1 ($string) of type string is deprecated" as of PHP 8.1.0
// int(0)
var_dump(str_contains("foobar", null));
// "Deprecated: Passing null to parameter #2 ($needle) of type string is deprecated" as of PHP 8.1.0
// bool(true)
?>
]]>
</programlisting>
</informalexample>
</note>
<sect2 role="seealso">
&reftitle.seealso;
<para>
<simplelist>
<member><function>function_exists</function></member>
<member><link linkend="funcref">関数リファレンス</link></member>
<member><function>get_extension_funcs</function></member>
<member><function>dl</function></member>
</simplelist>
</para>
</sect2>
</sect1>
<sect1 xml:id="functions.anonymous">
<title>無名関数</title>
<simpara>
無名関数は<literal>クロージャ</literal>とも呼ばれ、
関数名を指定せずに関数を作成できるようにするものです。
<type>callable</type>
パラメータとして使う際に便利ですが、用途はそれにとどまりません。
</simpara>
<simpara>
無名関数の実装には <link linkend="class.closure">
<classname>Closure</classname></link> クラスを使っています。
</simpara>
<example>
<title>無名関数の例</title>
<programlisting role="php">
<![CDATA[
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// helloWorld と出力します
?>
]]>
</programlisting>
</example>
<simpara>
クロージャは、変数の値として使用することもできます。
PHP は、そのような記述があると自動的に内部クラス
<classname>Closure</classname> のインスタンスに変換します。
変数へのクロージャの代入は、他の代入と同じように記述し、
同じく最後にセミコロンをつけます。
</simpara>
<example>
<title>変数への無名関数の代入</title>
<programlisting role="php">
<![CDATA[
<?php
$greet = function($name) {
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
]]>
</programlisting>
</example>
<simpara>
クロージャは、変数を親のスコープから引き継ぐことができます。
引き継ぐ変数は、<literal>use</literal> で渡さなければなりません。
PHP 7.1 以降は、引き継ぐ値に &link.superglobals;
<varname>$this</varname>
およびパラメータと同じ名前の変数を含めてはいけません。
戻り値の型は、
<literal>use</literal><emphasis></emphasis>
に置かなければいけません。
</simpara>
<example>
<title>親のスコープからの変数の引き継ぎ</title>
<programlisting role="php">
<![CDATA[
<?php
$message = 'hello';
// "use" がない場合
$example = function () {
var_dump($message);
};
$example();
// $message を引き継ぎます
$example = function () use ($message) {
var_dump($message);
};
$example();
// 引き継がれた変数の値は、関数が定義された時点のものであり、
// 関数が呼ばれた時点のものではありません
$message = 'world';
$example();
// $message をリセットします
$message = 'hello';
// リファレンス渡しで引き継ぎます
$example = function () use (&$message) {
var_dump($message);
};
$example();
// 親のスコープで変更された値が、
// 関数呼び出しの内部にも反映されます
$message = 'world';
$example();
// クロージャは、通常の引数も受け付けます
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello");
// 戻り値の型は、use の後に置きます
$example = function () use ($message): string {
return "hello $message";
};
var_dump($example());
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"
string(11) "hello world"
]]>
</screen>
</example>
<para>
PHP 8.0.0 以降では、親のスコープを継承した変数の一覧の最後にカンマを付けられるようになりました。
このカンマは無視されます。
</para>
<simpara>
親のスコープからの変数の引き継ぎは、グローバル変数を使うのとは
<emphasis>異なります</emphasis>。グローバル変数は、
関数が実行されるかどうかにかかわらずグローバルスコープに存在します。
クロージャの親スコープは、クロージャが宣言されている関数です
(関数の呼び出し元のスコープである必要はありません)。
次の例を参照ください。
</simpara>
<example>
<title>クロージャのスコープ</title>
<programlisting role="php">
<![CDATA[
<?php
// 基本的なショッピングカートで、追加した商品の一覧や各商品の
// 数量を表示します。カート内の商品の合計金額を計算するメソッド
// では、クロージャをコールバックとして使用します。
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
public function getTotal($tax)
{
$total = 0.00;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
$my_cart = new Cart;
// カートに商品を追加します
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// 合計に消費税 5% を付加した金額を表示します
print $my_cart->getTotal(0.05) . "\n";
// 結果は 54.29 です
?>
]]>
</programlisting>
</example>
<example>
<title><literal>$this</literal> の自動バインド</title>
<programlisting role="php">
<![CDATA[
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
object(Test)#1 (0) {
}
]]>
</screen>
</example>
<para>
クラスのコンテキストで宣言した場合は、現在のクラスが自動的にバインドされて、
関数のスコープで <literal>$this</literal> が使えるようになります。
現在のクラスへの自動バインドを望まない場合は、
<link linkend="functions.anonymous-functions.static">static な無名関数</link>
を使いましょう。
</para>
<sect2 xml:id="functions.anonymous-functions.static">
<title>static な無名関数</title>
<para>
static を付けて無名関数を宣言することができます。
こうすることで、現在のクラスが無名関数を自動的にバインドすることがなくなります。
オブジェクトも、実行時にはバインドされなくなります。
</para>
<para>
<example>
<title>static な無名関数内での <literal>$this</literal> の使用例</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Notice: Undefined variable: this in %s on line %d
NULL
]]>
</screen>
</example>
</para>
<para>
<example>
<title>static な無名関数へのオブジェクトのバインド</title>
<programlisting role="php">
<![CDATA[
<?php
$func = static function() {
// 関数の本体
};
$func = $func->bindTo(new stdClass);
$func();
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Warning: Cannot bind an instance to a static closure in %s on line %d
]]>
</screen>
</example>
</para>
</sect2>
<sect2 role="changelog">
&reftitle.changelog;
<para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>8.3.0</entry>
<entry>
<link linkend="language.oop5.magic">マジックメソッド</link>
経由で作られたクロージャも、名前付き引数を受け入れるようになりました。
</entry>
</row>
<row>
<entry>7.1.0</entry>
<entry>
無名関数は、&link.superglobals; や、
<varname>$this</varname>, もしくは
引数と同じ名前の変数を use で引き継げなくなりました。
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect2>
<sect2 role="notes">
&reftitle.notes;
<note>
<simpara>
クロージャ内から <function>func_num_args</function>
<function>func_get_arg</function> および <function>func_get_args</function>
を使用することができます。
</simpara>
</note>
</sect2>
</sect1>
<sect1 xml:id="functions.arrow">
<title>アロー関数</title>
<simpara>
アロー関数は <link linkend="functions.anonymous">無名関数</link>
を簡潔に書ける文法として PHP 7.4 で追加されました。
</simpara>
<simpara>
無名関数とアロー関数は共に
<link linkend="class.closure"><classname>Closure</classname></link> クラスを使って実装されています。
</simpara>
<simpara>
アロー関数は
<code>fn (argument_list) =&gt; expr</code> という形で記述します。
</simpara>
<simpara>
アロー関数は
<link linkend="functions.anonymous">無名関数</link> と同じ機能をサポートしていますが、
親のスコープで使える変数が常に自動で使える点だけが異なります。
</simpara>
<simpara>
式の中で使える変数が親のスコープで定義されている場合、
暗黙のうちに参照ではなく値がキャプチャされます。
次の例では、<varname>$fn1</varname><varname>$fn2</varname> は同じ振る舞いをします。
</simpara>
<para>
<example>
<title>アロー関数は参照ではなく値を自動でキャプチャする</title>
<programlisting role="php">
<![CDATA[
<?php
$y = 1;
$fn1 = fn($x) => $x + $y;
// $y を値渡しするのと同じ
$fn2 = function ($x) use ($y) {
return $x + $y;
};
var_export($fn1(3));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
4
]]>
</screen>
</example>
</para>
<simpara>
この仕組みは、アロー関数をネストした場合でも同じ動きをします:
</simpara>
<para>
<example>
<title>アロー関数は、ネストされた場合でも変数を値でキャプチャする</title>
<programlisting role="php">
<![CDATA[
<?php
$z = 1;
$fn = fn($x) => fn($y) => $x * $y + $z;
// 51 を出力
var_export($fn(5)(10));
?>
]]>
</programlisting>
</example>
</para>
<simpara>
無名関数と同じように、
アロー関数の文法は、引数や戻り値、デフォルト値、可変長引数、
リファレンス渡しやリファレンス返しを含む、任意の関数シグネチャを扱えます。
次に示す例は、全て正しいアロー関数の例です:
</simpara>
<para>
<example>
<title>アロー関数の例</title>
<programlisting role="php">
<![CDATA[
<?php
fn(array $x) => $x;
static fn($x): int => $x;
fn($x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;
?>
]]>
</programlisting>
</example>
</para>
<simpara>
アロー関数は変数を値でバインドします。
これは変数 <varname>$x</varname> をアロー関数の内部で使うたびに
<code>use($x)</code> を実行することと大体同じです。
値でバインドするということは、アロー関数の外のスコープの値を変更することが不可能だということです。
参照でバインドしたい場合は、<link linkend="functions.anonymous">無名関数</link> が使えます。
</simpara>
<para>
<example>
<title>外部のスコープの値はアロー関数では変更できない</title>
<programlisting role="php">
<![CDATA[
<?php
$x = 1;
$fn = fn() => $x++; // 意味がない
$fn();
var_export($x); // 1 を出力
?>
]]>
</programlisting>
</example>
</para>
<sect2 role="changelog">
&reftitle.changelog;
<para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>7.4.0</entry>
<entry>
アロー関数が利用可能になりました。
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</sect2>
<sect2 role="notes">
&reftitle.notes;
<note>
<simpara>
アロー関数の内部から
<function>func_num_args</function>
<function>func_get_arg</function> および <function>func_get_args</function>
を使用することができます。
</simpara>
</note>
</sect2>
</sect1>
<sect1 xml:id="functions.first_class_callable_syntax">
<title>第一級callableを生成する記法</title>
<para>
第一級callableを生成する記法 (First class callable syntax) とは、PHP 8.1.0 で追加された、
<link linkend="language.types.callable">callable</link>
から <link linkend="functions.anonymous">無名関数</link> を生成する記法です。
この記法は、
文字列や配列を使って callable を生成するやり方を置き換えるものです。
この記法の利点は、callable の静的解析を行いやすくなることに加え、
そのスコープが、callable を生成した時点のスコープになることです。
</para>
<para>
<code>CallableExpr(...)</code> という記法で、
callable から <classname>Closure</classname> を生成します。
<code>CallableExpr</code> には、
PHP の文法上直接コールできるあらゆる式が使えます:
<example>
<title>簡単な例</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo {
public function method() {}
public static function staticmethod() {}
public function __invoke() {}
}
$obj = new Foo();
$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';
$f1 = strlen(...);
$f2 = $obj(...); // 呼び出し可能オブジェクト
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// 文字列や配列を使った、古い記法
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
<code>...</code> は文法の一部であり、省略形ではありません。
</para>
</note>
<para>
この記法の動作は、
<methodname>Closure::fromCallable</methodname>
の仕様に従います。
つまり、文字列や配列から callable を作るやり方とは異なり、
<code>CallableExpr(...)</code> のスコープは、
それを生成した時点でのスコープになります:
<example>
<title>古い callable の生成方法と、<code>CallableExpr(...)</code> の比較</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo {
public function getPrivateMethod() {
return [$this, 'privateMethod'];
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// 上記がエラーになるのは、呼び出しが Foo の外部から行われ、
// アクセス権のチェックもこの時点から行われるためです。
class Foo1 {
public function getPrivateMethod() {
// 下記は、callable を生成した時点のスコープになります。
return $this->privateMethod(...); // Closure::fromCallable([$this, 'privateMethod']); と同等です。
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
この記法を使ってオブジェクトを生成する操作
(例: <code>new Foo(...)</code>)
はサポートされていません。
なぜなら、<code>new Foo()</code>
は、呼び出しとは見なされないからです。
</para>
</note>
<note>
<para>
この記法は、<link linkend="language.oop5.basic.nullsafe">nullsafe 演算子</link> と組み合わせて使うことはできません。
以下のコードは、いずれもコンパイルエラーになります:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$obj?->method(...);
$obj?->prop->method(...);
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->