PHP入門 | 構造化とオブジェクト指向 | 関数で構造化する

プログラミングのレベルは何で決まるのだろうか。実は「分量」と言ってよい。全部で100行程度のプログラムならアマチュアでも書けるかもしれないが、1000行のプログラムは初心者には書けない。1万行のプログラムはプロでなければ難しい。これは使う関数が難しいとか、アルゴリズムが複雑だとかいう以前の問題である。つまり、「どれだけ大きなプログラムをきれいに整理し、把握できるように設計できるか」という問題である。

100行のプログラムは、ただ順番に書いていくだけでも作れる。PHPでいくつかフォームを送信するだけでも、すぐにそれくらいは書けるだろう。しかし1000行のプログラムは、そのような書き方では作れない。プログラムを役割ごとに整理し、必要に応じて必要な処理を呼び出す構造をきちんと考えて設計しなければならない。これが「構造化」という考え方である。

PHPで構造化の第一歩になるのは「関数」である。これまでただ並べて書いていたスクリプトを整理し、部分ごとに分けて「関数」として定義していくことで、全体をきれいでわかりやすく設計できるようになる。これが、より大きなプログラムを書けるようになる第一歩と言える。

関数といえば、これまでechoimplode/explodefopen/fcloseなど、さまざまなものが登場した。PHPでは基本的な機能はすべて関数として定義されている。この関数は、そのように「PHP本体に用意されているもの」だけではない。開発者が自分でスクリプトを書いて定義することもできる。関数は次のように定義する。

function 関数名(仮引数1, 仮引数2, ...) {
    ...... ここに実行する処理を書く ......
    ...... 結果を返すなら、最後にreturnする ......
}

関数を作るときに考えるべきことは「引数」と「戻り値」である。引数とは、関数を呼び出すときに渡される値である。たとえばfopen("data.txt");のように関数を呼び出すとき、必要な値を()に入れて呼び出してきた。これが引数である。

自分の関数を定義するときも、その関数にどのような値が必要かを考え、それを引数として指定する。関数の()内には、渡される値を受け取る変数を書く。これが「仮引数」である。関数を呼び出すと、引数に指定された値がこの仮引数の変数に割り当てられる。そして以後は、この変数を使って渡された引数の値を利用できる。

戻り値は、その関数を呼び出した側へ結果の値を返すものである。これは返したい値をreturn 値;のような形式で書く。このreturnは関数を抜け、指定された値を呼び出し元に返す。処理を抜けるため、returnの後に処理があっても実行されない。

それでは実際に関数を使ってみよう。まず、関数を使う前のソースコードを書いてみる。

<?php
    if ($_POST != null) {
        $str = $_POST['text1'];
        $str = htmlspecialchars(strtoupper($str));
         
        $result = str_replace('PHP', '<b>PHP</b>', $str);
    }
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <p><?php echo $result; ?></p>
        <hr>
        <p>ここにPHPという文字を含む文章を書いてください。</p>
        <form method="post" action="./index.php">
            <textarea name="text1"  cols="40" rows="5"><?php echo $str; ?></textarea>
            <br><input type="submit">
        </form>
        <hr>
    </body>
</html>

ここではテキストを送信すると、「PHP」というテキストをすべて太字で表示する。送信されたテキストをstr_replace関数で置換する簡単な例である。また、ここでは送られてきたテキストをstrtoupperという関数で処理している。これはアルファベットを大文字に変換して返す関数である。

関数の利点

それでは、例を関数で構造化して書いてみよう。構造化というほど大げさなものではないが、ソースコードは次のようになる。

<?php
    function getBoldStr($str) {
        $str = htmlspecialchars(strtoupper($str));
        $res = str_replace('PHP',  '<span style="font-weight:bold;color:red">PHP</span>', $str);
        return $res;
    }
 
    if ($_POST != null) {
        $str = $_POST['text1'];
    }
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1><?php echo getBoldStr("Hello PHP!"); ?></h1>
        <p><?php echo getBoldStr($str); ?></p>
        <hr>
        <p><?php echo getBoldStr("ここにPHPという文字を含む文章を書いてください。"); ?></p>
        <form method="post" action="./index.php">
            <textarea name="text1"  cols="40" rows="5"><?php echo $str; ?></textarea>
            <br><input type="submit">
        </form>
        <hr>
    </body>
</html>

今回は、変換される箇所がさらにわかりやすいように、PHPを太字かつ赤色で表示してみた。違いを見てみよう。

ここでは最初にfunction getBoldStr($str)という関数を定義している。引数には$strという仮引数を1つ用意した。この$strのテキストを置換し、完成したものをreturnで返す。呼び出している箇所を見ると、次のように書かれている。

<?php echo getBoldStr($str); ?>

getBoldStrの後に、必要な値を()で渡している。通常のPHPが提供する関数と、使い方がまったく変わらないことがわかる。

このように関数化することで、この処理はプログラムのどこからでも呼び出せるようになった。ここでは送信されたテキストの表示だけでなく、見出しや説明文もすべてこの関数で処理して出力している。関数化したため、同じ処理を何度も書く必要がなくなった。必要なときに呼び出せば、必要な処理を実行してくれる。これが関数化したときの利点である。

変数の使用範囲(スコープ)

このスクリプトをよく見ると、変数について少し面白いことに気づくだろう。関数の仮引数にも、それ以外の場所にも、$strという変数が使われている。同じ変数をこのように使っても、途中で値が書き換えられてしまう心配はないのだろうか。実は、関数内の$strと外部の$strは別の変数である。

変数には、それを使用できる範囲が決まっている。これを「スコープ」と呼ぶ。関数の中で変数を使う場合、その変数は関数内でだけ使用できる。その関数から抜けた時点で、その変数は消滅する。また、再びその関数を呼び出しても、前回呼び出したときの変数はきれいになくなっており、すべて新しく作られる。

したがって、関数の内部で作られ、その内部でだけ使われる変数を「ローカル変数」と呼ぶ。これに対して、関数の外部で作られ、スクリプト全体で使える変数を「グローバル変数」と呼ぶ。関数を利用する場合は、この「変数のスコープ」についてよく理解しておく必要がある。