関数の使い道(2)

関数の使い道(2)

先ほど、関数を使う利点を2つ挙げました。覚えていますか?

(1)同じ処理を書いたはずが間違ってしまうという可能性を防ぐことができる
(2)修正するときに一ヶ所を修正するだけで済む

関数を使う利点は、これだけではありません。

(3)プログラムの全体的な流れが見やすくなる

1回しか行わない処理であっても、関数にまとめることがよくあります。それは、プログラム全体の流れを把握しやすくするためです。少し長いですが、次のプログラムを見てください。何が目的のプログラムなのか判断しにくいと思います(分かりやすくするために日本語で書いていますが、このままではもちろん動きませんよ!)。

if (ユーザー名が入力されていない場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (ユーザー名が短すぎる場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (ユーザー名が長すぎる場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (ユーザー名に英数字以外の文字が含まれている場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (ユーザー名に不適切な文字列が含まれている場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (パスワードが入力されていない場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (パスワードが短すぎる場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (パスワードが長すぎる場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (パスワードに英数字以外の文字が含まれている場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (確認用パスワードが入力されていない場合) {
    エラー処理をする;
    プログラムを終了する;
}
if (確認用パスワードがパスワードと一致しない場合) {
    エラー処理をする;
    プログラムを終了する;
}
データベースへ接続する;
if (データベースへ接続できなかった場合) {
    エラー処理をする;
    プログラムを終了する;
}
データベースのトランザクション(邪魔が入らないようにする仕組み)を開始する;
ユーザー名とパスワードをデータベースに保存する;
if (データベースに保存できなかった場合) {
    エラー処理をする;
    プログラムを終了する;
}
データベースのトランザクションを終了する;
ユーザー登録完了画面を表示する;

読みにくいので、これを最後までまじめに読んでくれた方は、おそらくほとんどいないでしょう。これを関連する処理ごとに関数にまとめてみたものが以下になります。ぐっと読みやすくなりましたよね。関数の宣言を読まなくても、この処理の流れを理解することができます。

// 新規ユーザーの入力値をチェックする
$result = check_input_values(); //関数(1)
if ($result === false) {
    エラー処理をする;
    プログラムを終了する;
}
// データベースに新規ユーザーの情報を保存する
$result = save_userdata(); //関数(4)
if ($result === false) {
    エラー処理をする;
    プログラムを終了する;
}
ユーザー登録完了画面を表示する;
// 処理終了

// 関数(1):入力値をチェックする
function check_input_values() {
    // ユーザー名をチェックする
    $result = check_input_username(); //関数(2)
if ($result === false) {
        return false;
}
    // パスワードをチェックする
    $result = check_input_password(); //関数(3)
if ($result === false) {
        return false;
}
return true;
}

// 関数(2):ユーザー名をチェックする
function check_input_username() {
    if (ユーザー名が入力されていない場合) {
    else if (ユーザー名が短すぎる場合) {
    else if (ユーザー名が長すぎる場合) {
    else if (ユーザー名に英数字以外の文字が含まれている場合) {
    else if (ユーザー名に不適切な文字列が含まれている場合) {
        return false;
    }
    return true;
}

// 関数(3):パスワードをチェックする
function check_input_password() {
    if (パスワードが入力されていない場合) {
    else if (パスワードが短すぎる場合) {
    else if (パスワードが長すぎる場合) {
    else if (パスワードに英数字以外の文字が含まれている場合) {
    else if (確認用パスワードが入力されていない場合) {
    else if (確認用パスワードがパスワードと一致しない場合) {
        return false;
    }
    return true;
}

// 関数(4):データベースに新規ユーザーのデータを保存する
function save_userdata() {
    データベースへ接続する;
    if (データベースへ接続できなかった場合) {
        return false;
    }
    データベースのトランザクション(邪魔が入らないようにする仕組み)を開始する;
    ユーザー名とパスワードをデータベースに保存する;
    if (データベースに保存できなかった場合) {
        return false;
    }
    データベースのトランザクションを終了する;
    return true;
}

(4)関数の中身を別の人に書いてもらうことができる

ユーザー定義関数は、別のファイルに分けて書いておき、使うときに読み込むことができます。つまり引数に何を渡すのかと、関数が何を返すのかさえ決めておけば、その関数は自分で書かずに別の人に書いてもらうことができます。うまく分業できるということですね。

関数内での変数のスコープ

どのプログラミング言語でも、その言語の「スコープ」のルールは絶対に押さえておくべきです。スコープとは変数などの影響範囲のことです。これが分からないと、思うようにコードが書けません。

まずこのコードを見て、最後の行で何が出力されるか当ててみてください。

$hello = "こんにちは";
function hello_in_english() {
    $hello = "hello";
}
echo $hello;

正解は「こんにちは」です。関数「hello_in_english」はただそこに宣言されているだけで、実行されていません。存在しないのと同じです。

ではこれはどうでしょう。

function hello_in_english () {
    $hello = "hello";
}
$hello = "こんにちは";
hello_in_english ();
echo $hello;

これも「こんにちは」と出力されます。関数「hello_in_english」が実行されていますが、関数の中の$helloと関数の外の$helloは、名前は同じでも別物です。PHPのスコープでは、関数の中で同じ名前の変数をいじくり回しても、関数の外の同じ名前の変数に影響を与えません。このおかげで、他の人が作った関数の中にどんな名前の変数があるのかを気にせずに、安心してその関数を使うことができるのです。

少し難易度を上げます。これは何が出力されるでしょうか。

function hello_in_english ($hello) {
    $hello = "hello";
}
$hello = "こんにちは";
hello_in_english ($hello);
    echo $hello;

これも答えは「こんにちは」です。関数「hello_in_english」の引数の$helloを指定していますが、これは変数$helloを関数に渡しているのではなくて、変数の中身の値「こんにちは」を渡しています。そのため、関数「hello_in_english」の中では最初$helloに「こんにちは」が入りますが、すぐに「hello」で上書きされます。しかしその$helloは何かに使われることもなく、関数が終了しています。つまりこの関数は、実質何もしていません。

それでは、次の処理の結果はどうなるでしょうか。

function hello_in_english () {
    echo $hello;
}
$hello = "こんにちは";
hello_in_english ();

関数の中から関数の外の変数は扱えないので、echoの対象は空っぽになります。よって、何も出力されません。

以下のようにすれば、関数「hello_in_english」に「こんにちは」が渡されるので、「こんにちは」と出力されます。

function hello_in_english ($hello) {
    echo $hello;
}
$hello = "こんにちは";
hello_in_english ($hello);

くどいようですが、渡しているのは変数$helloではなく、変数の中身の「こんにちは」です。

実は変数自体を渡す方法もあります。少し高度な使い方であり、関数の外の変数に影響を与えてしまうので、注意して使ってください。

function hello_in_english (&$hello) {
    $hello = "hello";
}
$hello = "こんにちは";
hello_in_english ($hello);
echo $hello; // →hello

関数の宣言時に引数に「&」を付けると、変数の中身ではなく変数そのものを渡すようになります。

これまでの例を見て、「いちいち引数で渡すのは面倒だ」と思いましたか。使用目的は限られますが、引数で渡さない方法もあります。それは、グローバル変数を使う方法です。スコープの一番外側を「グローバルスコープ」と言いますが、そこで宣言された変数は以下のように指定すると、関数の中からも参照や変更ができます。

<?php
// ここがグローバルスコープ
$hello = "こんにちは";
function hello_in_english() {
    // 関数の中はまた別のスコープ
    // 関数の外の変数は参照できない
    echo $hello; // →出力なし
    // グローバル変数を通して参照できる
    echo $GLOBALS["hello"]; // →こんにちは
    // 変更もできる
    $GLOBALS["hello"] = "hello";
}
hello_in_english();
echo $hello; // →hello

$GLOBALSを使わず、グローバル変数に「global」を付けて宣言する方法もあります。最初に宣言が必要ですが、$GLOBALSよりも見た目がすっきりします。

<?php
$hello = "こんにちは";
function hello_in_english() {
    // グローバル変数の$helloを使うと宣言する
    global $hello;
    // グローバルスコープにある$helloを参照できるようになる
    echo $hello; // →こんにちは
    // 変更もできる
    $hello = "hello";
}
hello_in_english();
echo $hello; // →hello

おわりに

いかがでしたか。今回までの内容で、基本的なPHPの操作を覚えることができました。次回からは、Webアプリケーションに特有の処理が増えてきますよ。お楽しみに。それではまた。

この記事のキーワード :

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored

ClickHouse Cloudが実現した広告運用SaaS「ATOM」のデータ基盤革新、パフォーマンスを向上しながら、運用負荷とコストを削減 11月11日 6:20 AIで開発が加速する時代、品質保証はどう変わる? Tricentisが示すAIエージェント活用の実像 11月9日 6:45 悪用までの猶予が「1分」に迫るフロンティアAI時代に開発と本番を貫く脆弱性管理が必要 10月29日 8:30 欧州CRA対応とSBOM運用。AI生成コードのOSS混入問題の対策とは ――スニペット単位で検出する「FossID」「Insignary Clarity」によるSBOM運用 9月16日 6:40 PostgreSQLからTiDBへ、稼働中SaaSで進める段階的DB移行の実践と再設計への展望 9月7日 6:30 機能安全開発におけるGoogleTestの活用を支援!「Parasoft C/C++test CT」で実現する効率化&AI連携 4月14日 6:30 【CNDW2025】Grafanaが明かす「オブザーバビリティの哲学」ー最小限の労力で実用的なインサイトを得るには 1月23日 6:30 【CNDW2025】プロダクト急増に備える基盤刷新 ーウェルスナビがECSからEKSへの移行で得た知見とは 1月15日 6:30 【CNDW2025】250環境を5人で運用、構築時間は30分に ーKINTOテクノロジーズが語るインフラ基盤組織の作り方 2025年12月18日 6:30 新たな自動化で熱視線! AIエージェントの「推論能力」を支える2つのコンポーネントとは? 2025年11月28日 6:30