PHP5上級試験/準上級試験の上級合格に挑戦(4)　３章関数後編


# 前回
[上級Ⅱ3章関数前編](https://qiita.com/Atsulabo/items/1697299314441ff22105)

+ 副作用をもつ関数
+ 関数表記方法・変数との表記方法の違い

[上級Ⅱ3章関数中編](https://qiita.com/Atsulabo/items/1d8d5cd016f556358380)

+ スコープ
+ スタティック
+ 上記２つの複合応用問題

※今まで受けてきた中で関数だと、複合応用問題、関数と変数表記方法が主に出題されてると思う

# 関数後編

## 入れ子
+ 関数の中に別の関数を定義すること
+ 入れ子にした関数を呼び出すには先にそれを含む関数を呼び出す

下記の出力はどうなるか。

```index.php
//(1)
function x(){
 function y(){
   echo 'ご機嫌';
 }
}
x();
y();

//(2)
function x(){
 function y(){
   echo 'ご機嫌';
 }
}
y();

//(3)
function x(){
 function y(){
   echo 'ご機嫌';
 }
}
x();

```
（１）ご機嫌が出力
（２）エラー終了
（３）エラーはないが、ご機嫌も出力されない
→つまり、ｘ（）だけでもｙ（）だけでもだめで、まず先にx（）を呼び出し、つぎにy()を呼び出さないといけない

## 値渡しと参照渡し

+ 値渡しはコピー、参照渡しはそっくりそのまま渡すイメージ
+ デフォルトはもちろん値渡し
+ マクロで言う、byVal,byRef
+ 値渡しはデフォルトそのまま、参照渡しはパラメータの前に&(アンパサンド）をつける

いつものどおり下記の出力を答えてください

```index.php
//(1)値渡し
function test($arr) {
  $arr++;
 }
$x = 20;
test($x);
echo $x;

//(２)参照渡し
function test2(&$arr) {
  $arr++;
 }
$x = 20;
test2($x);
echo $x;

```
　 

 　
 　

上記では、仮引数のほうで（１）のほうは＄arrで、値渡し、（２）は&$arrと、参照渡し。
値渡しはコピーを渡しただけなので、外側にある＄ｘは２０のまま。
参照渡しはまるごと渡すので、関数内で１こふえてるので２１に。
結果、「２０２１」となる。（改行してないので）

## パラメータのデフォルト値

+ パラメータのデフォルト値を決めておいて省略されたときにそれを渡せる
+ マクロで言うOptional

いつものどおり下記の出力を答えてください

```index.php
//(1)
function test($x=1,$y=200,$z=300) {
  echo '$x='.$x.'<br>';
  echo '$y='.$y.'<br>';
  echo '$z='.$z.'<br>';
 }
test(1,2,3);
test(1,2);
test(1);

//(２)
function test($x=1,$y=200,$z=300) {
  echo '$x='.$x.'<br>';
  echo '$y='.$y.'<br>';
  echo '$z='.$z.'<br>';
 }
test(,2);
test(３,,2);

```
(1) ここはまあ簡単でしょう 
$x=1

$y=2

$z=3

$x=1

$y=2

$z=300

$x=1

$y=200

$z=300

(2) 
エラー終了。
このように、頭部分を省略するという書き方はできない。
<b>デフォルト値を持つパラメータに対する引数の指定を省略した場合は、それ以降の引数の指定もすべて省略しないといけない。</b>
つまり、（２）のように、１番目を省略したら続く引数も省略しないといけないってこと。

## パラメータと引数の関係

+ 関数のパラメータの数　> 引数　→　指定されなかったパラメータは未設定のまま処理続行<b>(警告あり）</b>
+ 関数のパラメータの数　< 引数　→　あまった引数は無視<b>（警告はなし）</b>

いつものどおり下記の出力を答えてください

```index.php
//(1)
function test($x,$y) {
  echo '$x='.$x.'<br>';
  echo '$y='.$y.'<br>';
  echo '$z='.$z.'<br>';
 }
test(1,2,3);
test(1);
test();

```
エラー終了しなかったが、ログを見ると警告が２つ発生
そして、出力はtest(1,2,3)のみだった。それが下記。


$x=1
$y=2
$z=

## 可変パラメータ

+ 関数が不特定の数のパラメータを必要とするときに利用
+ 「func_num_args()」「func_get_arg()」「func_get_args()」の３つを使う
+ func_num_args()は関数にはいってる引数の数を取得
+ func_get_arg($arg_num)は指定した番号の引数の値を取得。引数は○番目かを指定。Forと一緒に
+ func_get_args()は引数リストを配列化。foreachと一緒に使うことが多いハズ


上記の関数を使って下記コードを書いた

```index.php
function test()
{
    $args_num = func_num_args();
    echo "引数の数: $args_num<br>";

    $args_2num  = func_get_arg(1); //２番めの引数を指定
    echo "２番めの引数:$args_2num<br>";

    $args = func_get_args();
    foreach ($args as $s){
      echo $s.",<br>";
    }
}

test(1, 2);
echo "<br>";
test(1,2,3,4,5);
echo "<br>";


```
こちらの出力は

引数の数: 2
1番めの引数:2
1,
2,

引数の数: 5
1番めの引数:2
1,
2,
3,
4,
5,

となる


## その他
### return
 + 英語のとおり、返り値を渡せる
 + 返り値が不要でも、このreturn;だけで、その関数を終了させることができる
 + 関数末尾の場合returnがなくてもOK
 + 複数の値を帰す場合はarray()で。カンマ区切りのはない
 + デフォルトで関数からの値はコピー。
 + 参照渡しにしたいなら、先程の通り、関数名の前に&(アンパサンド）をつける。
 + 関数呼び出し側でも関数名の前に＆（アンパサンド）をつける。

```index.php

function &test(&$x){
  return $x;
}

$x = 1;
$result = &test($x);
$x = 2;
echo $result;

```
$resultに＆test()という関数が格納されているので、
最後の行ではtest()が参照渡しの状態で実行される
したがってこの出力は２になる

### 可変関数

+ 関数の名前を変数に代入したもの
+ 指定した関数名に対応する関数がないとエラーになる
+ 関数があるかどうかを調べるのはfunction_exists(function_name)でいける
+ また言語構造であるecho()やisset()はこれで呼び出せない

※言語構造とは言語を構成する要素のこと。トークンと言い換えてもいいかも。
 例としてifとかforとかある。
 紛らわしい例として、echo/isset以外に、print/unset/dieなど。動詞っぽいから紛らわしい。
 覚えるしかないが、よく使うのは上のようなものぐらいだと思う。一応下で確認しておこう。
 これらは関数ではないので、カッコでくくってもくくらなくてもよい、とされている。
 参考→[キーワードリスト](https://www.php.net/manual/ja/reserved.keywords.php)
 ここにあるのは全部言語構造だそう。

```index.php
//(1)
function test()
{
  $test_name = 'print';
  $test_name('ご機嫌');
}

//(2)
$test_name = 'print';
if (function_exists($test_name){
  $test_name('ご機嫌');
} else {
  $test_name,'は未定義です';
}

//(3)
$test_name = 'echo';
$test_name('ご機嫌');

```
(1)が基本。もちろんご機嫌が出力。
（２）も同じくご機嫌が出力。関数があるか確かめてから実行してる点に注目。
（３）エラー。echoやissetはだめ。


###　匿名関数

+ 他の関数と重複しないランダムな名前が割り振られる
+ create_fucntion()で作成
+ パラメータリストで指定されたパラメータと、コードで作成
+ create_fucntion(string $args,string $code);
+ array_filter()などの関数の引数として使用

```index.php

$Myfunc = create_function('$x'.'echo $x;);
$Myfunc('hello');

$Myfunc2 = create_function('x', 'return $x >= 80);
$a = array(78,79,80.81,82);
$b = array_filter($a,$Myfunc2);
printf($b);

```

出力は
Hello,2=>80, 3=>81, 4=82となる


#　今後
[上級Ⅱ3章関数前編](https://qiita.com/Atsulabo/items/1697299314441ff22105)

+ 副作用をもつ関数
+ 関数表記方法・変数との表記方法の違い

[上級Ⅱ3章関数中編](https://qiita.com/Atsulabo/items/1d8d5cd016f556358380)

+ スコープ
+ スタティック
+ 上記２つの複合応用問題

上級ⅡⅣ関数後編は下記の通り

+ 入れ子
+ ご機嫌
+ 値渡しと参照渡し
+ パラメータのデフォルト値
+ パラメータと引数の関係
+ 可変パラメータ
+ return
+ 可変関数
+ 匿名関数

長かったけど、これで３章終わり。
引っかかりやすいなーというところは、
可変パラメータ、可変関数だと思います。

頑張って覚えましょう！