ゼロから始めるPHP講座Vol.40 ユーザー定義関数①


ゼロから始めるPHP講座Vol.40 ユーザー定義関数①
目次
  1. ゼロから始めるPHP講座ユーザー定義関数①
  2. ユーザー定義関数
  3. ユーザ定義関数の書き方
  4. ユーザー定義関数の利点
  5. スコープ
  6. 定数
  7. 課題

ゼロから始めるPHP講座ユーザー定義関数①

ユーザー定義関数

PHPにはたくさんの関数が用意されており、date関数、mt_rand関数、preg_match関数、etc.と、これまで色々な関数を利用してきました。

非常に便利な関数ですが、実は自分で関数を作る(定義する)ことができ、これをユーザー定義関数と呼びます。

まずはお手本にある通り、ユーザー定義関数を使ったプログラムを書いてみましょう。

ファイル名:func.php

<pre>
<?php

print_hello();

print_hello_name('山田');

$return_hello_name = return_hello_name('鈴木');
print $return_hello_name . "\n";

function print_hello() {
    print 'print_hello関数: hello' . "\n";
}

function print_hello_name($name) {
    print 'print_hello_name関数: hello ' . $name . "\n";
}

function return_hello_name($name) {
    $str = 'return_hello_name関数: hello ' . $name . "\n";
    return $str;
}

?>
</pre>

php_func_application1-639

print_hello関数、print_hello_name関数、return_hello_name関数を独自に定義し、これを実行しています。

ユーザ定義関数の書き方

ユーザー定義関数は以下のような書式で記述します。

php_func_application2-639

「関数名」は自分で関数の名前を付けます。変数と同じく、名前には英数字か_(アンダースコア)を利用できます。関数名は大文字小文字を区別しませんが、関数宣言時と同じ名前で関数をコールする方が好ましいです。

「引数」は関数に渡す値です。詳しくは後ほど説明します。

「処理」の部分に、関数にさせたい処理内容を記述します。

変数と異なり、一度定義した関数の再定義はできません。

定義した関数の実行は「関数名(引数)」と、PHPで用意されている関数と同じ記述方法です。

php_func_application3-639

print_hello関数の内容は、

処理 挨拶を表示する

引数 なし

返り値 なし

となります。

print_hello関数の引数はありません。引数は必ず指定しなければいけないわけではなく、なしにすることも可能です。

「print_hello()」と括弧の中身を空にすることで、引数なし関数の定義や実行をすることができます。

print_hello_name関数は、

php_func_application4-639

処理 挨拶 + 名前 を表示する

引数 $name (名前)

返り値 なし

となります。

引数は関数実行時に指定された値を受け取る役割を持っています。

「$name=‘山田’;」と、実行時に指定された値をfunctionで定義した引数(変数)に代入しているイメージです。

return_hello_name関数は、

php_func_application5-639

処理 挨拶 + 名前 の文字列を返す

引数 $name (名前)

返り値 挨拶 + 名前の文字列

となります。

関数の中に「return」を記述することで関数を実行した際に値を返すことができ、この値を返り値と呼びます。サンプルでは$return_hello_nameに返り値を代入しています。

returnが実行されると、以降に記述されている処理は行われません。実際にreturn以降にprintを行っても文字は表示されません。

なお今回は理解優先のため変数$strへ一度代入した後にreturnするサンプルとなっていますが、変数は同じ値を2回以上利用する際に使用するものであり、今回のように1回しか使わない値は変数に代入すべきではありません。

php_func_application6-639

具体的には上記のように変数へ代入せず直接returnすることにより、より短く無駄のないプログラムとなります。

まずは関数の仕組みと使い方を理解することが優先ですが、関数は工夫するポイントが多くありますので、これも少しずつ覚えていきましょう。

ユーザー定義関数の利点

ユーザー定義関数には様々な利点がありますが、代表的なものは以下となります。

  • プログラムが読みやすくなる
  • コード(関数)の使い回しができる
  • 変更箇所が少なくなる

本章では利点のおおまかなイメージと関数の使い方を掴む程度とし、詳細は次の章で説明します。

まずはお手本にある通り、プログラムを作成してみましょう。

ファイル名:entity.php

<?php
$h1 = '「<h1>見出し</h1>」は見出しを表します。';
$p  = '「<p>段落</p>」は段落を表します。';
$li = '「<li>リスト項目</li>」はリストの項目を表します。';

// 特殊文字をHTMLエンティティに変換
$h1 = entity($h1);
$p  = entity($p);
$li = entity($li);

function entity($str) {
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>HTMLエンティティ</title>
</head>
<body>
    <p><?php print $h1; ?></p>
    <p><?php print $p; ?></p>
    <p><?php print $li; ?></p>
</body>
</html>

php_func_application7-639

「entity」というユーザー定義関数を作成しました。

この関数はhtmlspecialchars関数による「<」や「>」などの特殊文字の変換を行っています。

関数としてまとめることで、例えば文字コードがUTF-8から変更になった場合、変更箇所が一箇所だけで済みます。また今後この関数を使いまわすことも可能です。

もう少し関数の利点や使い方について理解を深めるため、お手本にある通り次のプログラムを作成してましょう。

ファイル名:dice.php

&lt;pre&gt;
&lt;?php

print 'サイコロを1個振る:' . throw_dice(1) . "\n";
print 'サイコロを1個振る:' . throw_dice(1) . "\n";
print 'サイコロを2個振る:' . throw_dice(2) . "\n";
print 'サイコロを2個振る:' . throw_dice(2) . "\n";
print 'サイコロを3個振る:' . throw_dice(3) . "\n";
print 'サイコロを3個振る:' . throw_dice(3) . "\n";

function throw_dice($num) {

    $sum = 0;

    for ($i = 0; $i &lt; $num; $i++) {
        $sum += mt_rand(1,6);
    }

    return $sum;

}
?&gt;
&lt;/pre&gt;

php_func_application8-639

引数で指定個数のサイコロを振り、この合計値を表示しています。

php_func_application9-639

throw_dice関数の内容は、

処理 サイコロを指定回数振った合計値を計算する

引数 サイコロ個数

返り値 サイコロの合計値

となります。

同じような処理をthrow_dice関数にまとめることで、プログラムが読みやすくなりました。

またコード(関数)の使い回しにより、コードを短くすることができます。

スコープ

変数には有効範囲(スコープ)があり、有効範囲が異なると変数が参照できなくなります。

これまで関数外で定義していた変数はグローバル変数と呼ばれ、プログラムのどこからでも参照できていました。

しかし関数内で変数を利用する場合、これまでと有効範囲が異なってきます。


&lt;?php
$str = 'スコープテスト'; // 関数外で変数定義(グローバル変数)

function test_scope() {
    print $str; // 関数内の変数を参照
}

test_scope();
?&gt;

例えば上記プログラムを作成し実行すると、「Notice:Undefinedvariable:str…」と変数が未定義という旨のエラーが表示され、「スコープテスト」という文字列は表示されません。

関数内と関数外では変数の有効範囲が異なっており、関数内で参照できる変数は、関数内で定義された変数のみとなります。

作成したtest_scope関数内で「print$str;」を行っていますが、printで探しているのは関数内で定義された変数であり(関数内に変数$strは存在しない)、関数外で定義されているグローバル変数$strは、有効範囲外となります。

関数内で作成した変数を関数外で利用する場合も、同じく有効範囲が異なります。

&lt;?php
function test_scope() {
    $str = 'スコープテスト'; // ローカル変数の定義
}

test_scope();
print $str; // グローバル変数の参照
?&gt;

上記プログラムを作成し実行すると、「Notice:Undefinedvariable:str…」と変数が未定義という旨のエラーが表示され、「スコープテスト」という文字列は表示されません。

関数内で定義された変数の有効範囲は、その関数内部に制限されます。

test_scope関数内で定義した変数$strの有効範囲はtest_scope関数内のみとなっており、関数外でtest_scope関数を実行した後に変数$strをprintしても、有効範囲が異なるため参照できません。

関数内などで定義し、有効範囲が限られた変数をローカル変数と呼びます。

このように関数外と関数内では有効範囲が異なりますが、グローバル変数は関数の内部で利用する方法があります。


&lt;?php
$str = 'スコープテスト'; // グローバル変数

function test_scope() {
    global $str; // グローバル宣言(グローバル変数を参照)
    print $str;
}

test_scope();
?&gt;

上記プログラムを作成し実行すると、「スコープテスト」という文字列が表示されます。

関数内で「global変数名;」とグローバル宣言を行うことで、ローカル変数ではなく、グローバル変数を参照するようになります。

ただし、グローバル宣言は、可能な限り利用しないべきです。

理由は様々あり、例えばソースコードの可読性が悪くなります。

変数の参照できる範囲(スコープ)が広がると、その変数がどこで何に使われているか確認するのが大変になります。「変数のスコープは必要最低限の範囲とする」を心がけてみてください。

また、スーパーグローバル変数は関数内や関数外を問わず、どこでも利用することができます。


&lt;?php
function test_scope() {
    print $_SERVER['REQUEST_METHOD']; // スーパーグローバル変数を参照
}

test_scope();
?&gt;

上記プログラムを作成し実行すると、「GET」とリクエストメソッドが表示されます。

スーパーグローバル変数は「プログラム実行時に自動的に定義され、プログラムのどこからでもアクセスできる変数」と以前説明しました。

「プログラムのどこからでもアクセスできる」というのは変数のスコープを指しており、関数外でも関数内でも利用することができます。

変数のスコープについてまとめると以下となります。

  • 変数には有効範囲(スコープ)があり、有効範囲が異なると参照できない
  • 関数外で定義し有効範囲に限りないがない変数をグローバル変数と呼ぶ
  • 関数内で定義し有効範囲が限られた変数をローカル変数と呼ぶ
  • ローカル変数は定義した関数内のみで参照できる
  • デフォルトではグローバル変数を関数内で参照できない
  • グローバル宣言を行うことにより、グローバル変数を関数内で参照できる
  • スーパーグローバル変数は関数内でも関数外でも参照できる

関数を利用する上でスコープの理解は重要です。

文章だとなかなか理解が難しいと思いますので、理解が足らないと思ったならば、実際にユーザー定義関数を作成し、試してみましょう。

なおスコープという概念はPHPだけでなくプログラミング全般に存在します。しかしその仕様は言語により異なる場合もあるため、別なプログラミング言語を学ぶ際は注意が必要です。

定数

定数は変数と同じくデータを格納するもので、一度値を定義すると変更できません。

php_func_application10-639

定数を定義するにはdefine関数を使います。

名前に利用できるのは変数と同じく英数字か_(アンダースコア)で、数字が使えるのは2文字目以降となります。

定数は小文字を利用せず、大文字のみで定義するのが一般的です。

実際に定数を使った下記プログラムを作成してみましょう。

ファイル名:define.php

&lt;?php
define('TAX', 1.05);  // 消費税

$price = 100;

print $price . '円の税込み価格は' . $price * TAX . '円です';
?&gt;

php_func_application11-639

「100円の税込み価格は105円です」と表示されます。定数は変数のように$記号をつける必要はなく、定数名をそのまま記載します。

また定数は一度値を定義した値をdefine関数で再定義しようとすると、エラーが発生します。

先ほどのプログラムに、定数TAXの再定義を追記してみましょう。

&lt;?php
define('TAX', 1.05);  // 消費税
define('TAX', 1.08);  // 消費税変更

$price = 100;

print $price . '円の税込み価格は' . $price * TAX . '円です';
?&gt;

php_func_application12-639

「Notice:ConstantTAXalreadydefined」と、既に定数TAXは定義されていますとエラーが表示された上で、「100円の税込み価格は105円です」と表示されます。

このようにdefine関数による再定義はエラーメッセージが出力され、値は変更されません。

また定数のスコープはスーパーグローバル変数と同じく、プログラムのどこからでもアクセスができます。

関数内で定数を利用するプログラムを作成してみましょう。

&lt;?php
define('TAX', 1.05);  // 消費税

$price = 100;

//print $price . '円の税込み価格は' . $price * TAX . '円です';
print $price . '円の税込み価格は' . price_before_tax($price). '円です';

function price_before_tax($price) {
    return $price * TAX;
}
?&gt;

php_func_application13-639

税込み価格を計算するprice_before_tax関数を定義しました。

定数TAXは関数外で定義していますが、price_before_tax関数内で参照できています。

課題

スコープの理解確認のため、お手本にあるプログラムを実行した場合、変数$a,$b,$c,$dと定数DEFについて、数値がどう変化するか予測をしてください。(下記で「?」となっている部分を予測)

ファイル名:challenge_scope.php

&lt;pre&gt;
&lt;?php
$a = 10;
$b = 10;
$c = 10;
$d = 10;
define('DEF', 10);

print 'fuga_before: a = ' . $a . "\n";
print 'fuga_before: b = ' . $b . "\n";
print 'fuga_before: c = ' . $c . "\n";
print 'fuga_before: d = ' . $d . "\n";
print 'fuga_before: DEF = ' . DEF . "\n";

fuga($c);

print 'fuga_after: a = ' . $a . "\n";
print 'fuga_after: b = ' . $b . "\n";
print 'fuga_after: c = ' . $c . "\n";
print 'fuga_after: d = ' . $d . "\n";
print 'fuga_after: DEF = ' . DEF . "\n";

function fuga($c) {

global $d;

$a++;
print 'fuga: a = ' . $a . "\n";

$b = 100;
$b++;
print 'fuga: b = ' . $b . "\n";

$c++;
print 'fuga: c = ' . $c . "\n";

$d++;
print 'fuga: d = ' . $d . "\n";

define('DEF', 100);
print 'fuga: DEF = ' . DEF . "\n";
}
?&gt;
&lt;/pre&gt;

php_func_application14-639

予測が完了したら、プログラムを作成し、実行してください。

NEXTLESSONユーザー定義関数②ユーザー定義関数②

PREVLESSONトランザクション応用トランザクション応用


CodeCampus編集部
この記事を書いた人
CodeCampus編集部
まずは7日間お試し!人気プログラミング講座を無料公開中
オンライン・プログラミングレッスンNo.1のCodeCamp