情報学部 菅沼ホーム 目次 索引

PHP 概説

      1. PHP の特徴とその使用方法
        1. Web ページへの埋め込み
        2. コマンドラインからの使用
      2. データ型
        1. 変数
        2. 使用可能な型
        3. 型変換
      3. 演算子
        1. 算術演算子と代入演算子
          1. [プログラム例 3.1] 簡単なプログラム
        2. 関係演算子,等値演算子,及び,論理演算子
        3. ビット演算子とシフト演算子
        4. その他
      4. 制御文
        1. 分岐
        2. 繰り返し
      5. 配列
        1. 1 次元配列
        2. 多次元配列
        3. 連想配列
      6. 関数
        1. [プログラム例 6.1] 関数(様々な引数)
        2. [プログラム例 6.2] 関数(関数名)
      7. クラス
        1. [プログラム例 7.1] クラスと継承
        2. [プログラム例 7.2] オブジェクトの複製
      8. 変数の有効範囲(スコープ)

  1. PHP の特徴とその使用方法

      PHP は,C/C++ とは異なり,「コンパイラによって,機械語に翻訳してから実行する」という作業は必要ではありません.エディタで作成したプログラムを,そのまま,インタプリータが 1 行ずつ解釈して実行していきます.従って,実行速度としては,どうしても C/C++ よりは遅くなりますが,その点をしのぐ様々な利点を持っています.

      その一つが,Web ページとの結びつきです.PHP は,C/C++のように,単独で動作させることもできますが,Web ページ( HTML ファイル)の中に埋め込んで動作させることも可能です.その点からは,JavaScript と似ていますが,Web ページへの埋め込み方法の違いだけではなく,非常に大きな違いがあります.それは,JavaScript はクライアント上で動作しますが,PHP はサーバ上で動作するといった点です.そのため,Web ページ上に埋め込まれた JavaScript のプログラムを,Web ページのソースコードを表示させることによって見ることが可能ですが,PHP の場合は,PHP によって生成された結果だけが表示され,ソースコードもその表示に対応したものになっていますので,クライアント側からは PHP のプログラムそのものを全く見ることができません.

    1. Web ページへの埋め込み

        ファイル(拡張子は,通常,php とする)内に PHP のプログラムを記述する場合は,
      <?php   // <? でも良い場合がある
      
      	ここに,PHP のプログラム
      ?>				
      のように記述します.PHP では,下の使用例(赤字の部分が PHP)に示すように,HTML 文書自体を PHP プログラムで操作(下の例では,<DD> 要素によって記述された文を繰り返している)したり,また,HTML 文書内に「 <?php echo 文字列 ?> 」の方法で,PHP 内の変数値を埋め込むことも可能です(16 行目参照).なお,PHP の設定によっては,「 <?php 」を「 <? 」,「 <?php echo 」を「 <?= 」と記述する省略形が可能ですが,基本的に避けた方が良いと思います.なお,HTML に関しては,適宜,「 HTML & CSS 」などを参照してください.
      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>PHPの例</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
      07	</HEAD>
      08	<BODY CLASS="white">
      09		<H1>PHPの例</H1>
      10		<DL>
      11			<DT>嗜好品
      12	<?php
      13		$fr = array ('リンゴ', 'ミカン', 'イチゴ');
      14		for ($i = 0; $i < 3; $i++) {
      15	?>
      16			<DD>果物: <?php echo $fr[$i]."\n" ?>
      17	<?php
      18		}
      19	?>
      20		</DL>
      21	</BODY>
      22	</HTML>
      				
      12,17 行目

        PHP のプログラムが始まることを示します.

      13 行目

        後に述べる配列変数の定義です.今の段階では,変数 $fr には,3 つの値(文字列),'リンゴ', 'ミカン', 'イチゴ' が記憶されている程度に考えてください.

      14 行目

        これも,後に述べる繰り返し文( for 文)の記述です.この文によって,14 行目~ 18 行目が,3 回繰り返されます.

      15,19 行目

        PHP のプログラムが終わることを示します.

      16 行目

        「 <?php 」と「 <? 」に挟まれた変数 $fr[$i] の値(最初は,'リンゴ')と文字列 "\n" は,ピリオドによって結合され,16 行目の最後に出力されます.これが 3 回繰り返されるため,以下に示すような 3 つの文ができあがります.なお,"\n" は,改行を表す特別の文字列であり,表示はされません.
      	<DD>果物: リンゴ
      	<DD>果物: ミカン
      	<DD>果物: イチゴ					
        16 行目に対する表示結果に見るように,JavaScript とは異なり,PHP プログラムはサーバ側で実行され,その結果だけがクライアント側に表示されます(PHP のプログラム自身を見ることは出来ない).したがって,上の例の場合,クライアント側に表示されたページのソースコードは以下のようになります.
      <!DOCTYPE HTML>
      <HTML>
      <HEAD>
      	<TITLE>PHPの例</TITLE>
      	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      	<LINK REL="stylesheet" TYPE="text/css" HREF="../../master.css">
      </HEAD>
      <BODY CLASS="white">
      	<H1>PHPの例</H1>
      	<DL>
      		<DT>嗜好品
      		<DD>果物: リンゴ
      		<DD>果物: ミカン
      		<DD>果物: イチゴ
      	</DL>
      </BODY>
      </HTML>
      				

    2. コマンドラインからの使用

        コマンドラインから,特定のファイルを実行したり,または,PHP コードを直接実行することが可能です.たとえば,ファイル echo.php の内容が,
      <?php
      	echo "test\n";
      ?>				
      であった場合,コマンドラインから,
      php echo.php				
      と入力すると,echo.php の内容が実行されます.また,コマンドラインから,
      php -r "echo 'test\n';"				
      のよう入力し,PHP コードを直接実行することも可能です.

  2. データ型

    1. 変数

        基本的に型宣言という考え方がありません.つまり,C/C++ や Java のように,変数や関数の戻り値の型を宣言する必要がありません.変数(変数名の最初は必ず「 $ 」でなければない)であれば,その変数に代入されたリテラルの型によって変数の型も決まってしまいます.

    2. 使用可能な型

        PHP で使用できる主要な型や特別な定数は以下に示す通りです.なお,配列やオブジェクトに関しては後ほど述べます.

      1. 数値: 10 進整数,8 進数( 0 で始まる),16 進数( 0x で始まる),浮動小数点数を使用できます.環境によって異なりますが,基本的に,整数は 4 バイト,浮動小数点数は 8 バイトで表現されます.

      2. 論理型boolean ): 値は true,または,false(大文字,小文字を区別しない)になりますが,以下のものはすべて false とみなされます(そのほかはすべて true).

        false,0,0.0,空の文字列,"0",NULL

      3. NULL: 変数が値を持たないことを表します.

      4. 文字列: 文字列は,シングルクォーテーションマーク ' 」,または,ダブルクォーテーションマーク " 」によって囲んで表現されます.以下に示すプログラム例(行番号は,説明のために付加したもの,以下同様)に見るように,シングルクォーテーションマークで囲まれた場合は,その内容がそのまま文字列の内容となりますが,ダブルクォーテーションマークで囲まれた場合はその内部のエスケープシーケンスや変数が評価されます.なお,ピリオド「 . 」によって文字列の結合が可能です.文字列を結合する演算子が + である言語が多いので気をつけてください.
        01	<?php
        02		$x = 123;
        03		echo '変数$xの値は ';  // そのまま出力
        04		echo $x."\n";
        05	//	echo "変数$xの値は ".$x."\n";  // 「$xの値は」を変数名とみなしている(エラー)
        06		echo "変数 $x の値は ".$x."\n";  // スペースで区切って変数を明確にする
        07		echo "変数 ${x} の値は ".$x."\n";  // 「{」と「}」で区切って変数を明確にする
        08		echo "変数 {$x} の値は ".$x."\n";  // 「{」と「}」で区切って変数を明確にする
        09		echo "変数 \$x の値は ".$x."\n";  // 「\」で「$」の機能を無効にする
        10	?>						
        上記のプログラムを実行すると,以下に示すような出力が得られます.echo は,文字列を出力する機能を持った文字列関数の一つです.なお,5 行目は,「$xの値は」が一つの変数とみなされ,かつ,そのような変数が定義されていないためエラーとなります.
        変数$xの値は 123
        変数 123
        変数 123 の値は 123
        変数 123 の値は 123
        変数 123 の値は 123
        変数 $x の値は 123					

    3. 型変換

        PHP で行える型変換キャスト演算子)は,以下に示す通りです.

      • (int), (integer) : 整数へのキャスト
      • (bool), (boolean) : 論理値へのキャスト
      • (float), (double), (real) : floatへのキャスト
      • (string) : 文字列へのキャスト
      • (array) : 配列へのキャスト
      • (object) : オブジェクトへのキャスト

  3. 演算子

        整数同士の除算であっても,C/C++ のように,小数点以下が切り捨てられないことに注意してください.また,C/C++ と同様,演算と代入を同時に行う演算子,例えば,「 x += 10; 」なども使用可能です.

    1. 算術演算子代入演算子算術演算子と代入演算子
      . : 文字列の結合
      + : 加算(配列の場合は要素の和集合,後述)
      - : 減算
      * : 乗算
      / : 除算  小数点以下が常に計算される(以下に示すいずれかの方法で小数点以下切り捨て)
                  ( floor($x / $y),intval($x / $y),(int)($x / $y),(integer)($x / $y) )
      % : 余り  被除数,除数を共に整数型に変換(小数点以下を切り捨て)してから計算
                  ( 7.3 % 2.3 は,1 )
      = : 代入
      ++ : インクリメント演算子( 1 だけ増加)
      -- : デクリメント演算子( 1 だけ減少)				

      プログラム例 3.1] 簡単なプログラム

        ここまでの学習を終えたところで,2 つのデータを与えると,乗算と除算の結果を出力するという簡単なプログラムを書いてみましょう.PHP においても,その基本は C/C++ と同じです.入出力の方法が,多少,異なっている程度です.なお,今後,プログラム例を示すときに,01,20 行目に対応する部分を省略することも多いかと思いますが,実行するときは必ず入れてください.
      01	<?php
      02		/****************************/
      03		/* 2つのデータの乗算と除算 */
      04		/*      coded by Y.Suganuma */
      05		/****************************/
      06				// データの入力
      07		printf("2つのデータを入力して下さい ");
      08	//	echo "2つのデータを入力して下さい ";   // echo ("2つの...") でも可,以下同様
      09	//	print "2つのデータを入力して下さい ";
      10		$str = trim(fgets(STDIN));
      11		$x   = intval(strtok($str, " "));   // 小数点以下切り捨て
      12		$y   = intval(strtok(" "));   // 小数点以下切り捨て
      13				// 乗算と除算
      14		$mul = $x * $y;
      15		$div = $x / $y;
      16				// 結果の出力
      17		printf("乗算=%d 除算=%d %.3f\n", $mul, $div, $div);
      18		echo "乗算=".$mul." 除算=".$div."\n";
      19		print "乗算=".$mul." 除算=".$div."\n";
      20	?>
      				
      01,20 行目

        PHP プログラムの開始と終了を表す記号です.HTML ファイル内に埋め込まないときにも必ず必要です.

      02 行目~ 05 行目

        プログラム全体に対する注釈コメント)です.PHP の注釈は,この例のように, /* */ と囲んで表現します(複数行にわたっても良い).また,08 行目,09 行目,13 行目,... のように, // から行末までという表現方法も可能です.

        注釈は,プログラムの該当する部分における処理内容を説明するのに使用され,人間がプログラムを読む際,理解しやすくするためのものであり,コンパイラ等によって特別な処理はされません.プログラムを実行するのはコンピュータですが,プログラムを書いたり修正したりするのは人間です.従って,プログラムを書く際に最も注意すべきことは,いかに読み易く,かつ,分かり易いプログラムを書くかという点です.できるだけ多くの注釈を入れておいて下さい.そのことにより,他の人がプログラムを理解しやすくなると共に,プログラム上のエラーも少なくなるはずです.

      07 行目,17 行目

        2 つのデータを入力するためだけであれば,10 行目~ 12 行目だけで十分ですが,その場合,何のメッセージも出力されずキーボードからの入力待ちになってしまうため,一見コンピュータが止まってしまったように感じます.また,多くの入力を要求するような場合は,どの入力を要求しているのかが分かりません.そのため,07 行目の文字列関数 printf が使用されています.また,17 行目は,結果を出力するための printf です.関数は,外部から与えられたデータに基づき,何らかの処理を行いその結果を返します.関数にデータを与える方法の一つが引数です(以下の例において,printf の後ろの括弧内に書かれた部分).なお,これらの文のように,一般的に,PHP における一つの文の終わりにはセミコロン ; 」を付ける必要があります.

        標準入出力装置(一般的には,キーボードとディスプレイ)に対して入出力を行う場合,対象とするものは文字列です.キーボードから入力する場合,たとえ数値であっても,2 進数を使用したコンピュータの内部表現ではなく,例えば 123.45 のように,我々が読むことができる文字列として入力します.しかし,数値データを,入力された文字列としてそのまま記憶したならば,演算等を行うことができません.そのため,入力された文字列をコンピュータ内部で使用する表現方法に変換して記憶してやる必要があります.例えば,123.45 という文字列を数値として扱いたければ,動小数点表現に変換して記憶しておく必要があります.また,ディスプレイに出力する場合も,メモリ(変数)に記憶されているデータを文字列に変換して出力します.さもなければ,我々は,0 と 1 の並びとして出力される結果を自分自身で解釈しなければなりません.printf を使用する場合,C++ における printf と同様,記憶されたデータを文字列に変換する操作を指定してやる必要があります.

        07 行目の printf は,入力を促すメッセージを出力するだけです.17 行目では,$mul と $div の値を出力しています.17 行目の " の中の最後の記号 \n も 1 文字を表し,そのまま出力されますが, \ の付いた記号は,エスケープシーケンスといって,特別な働きをします.例えば, \n が出力されると改行が行われます.また,14 行目,15 行目を省略し,17 行目の $mul と $div の代わりに,($x * $y),($x / $y) という式を記述することも可能です.

      08 行目~ 09 行目,18 行目~ 19 行目

        12 行目,17 行目の代わりに,これらの行のいずれかを使用することもできます.echoprint は,文字列を出力するための言語構造です(関数と同じように,括弧で囲んでも構わない).18 行目~ 19 行目においては,$mul や $div の値が自動的に文字列に変換され,それらが . 演算子によって文字列として結合され,その結果が出力されます.

      10 行目

        fgets は,ストリームから 1 行分のデータを読み込むための関数です.ストリームとして SDTIN を指定することによって,標準入力からの入力が可能になります.この行を実行することによって,標準入力装置から入力した 1 行分のデータが,文字列として変数 $str に記憶されます.

        PHP のようなインタプリタでは,C++ のような型宣言を行う必要がありません.変数にデータを代入することによって,その変数の型が決まります.変数 $str には,文字列が代入されていますので,$str の型は文字列型になります.また,この行に示すように,PHP における変数名は,必ず $ から始まります.なお,trim は,文字列の前後の空白や改行を取り除くための関数です.

        この例の場合は,
      	fscanf(STDIN, "%d %d", $x, $y);					
      のように,fscanf(STDIN, ・・・ ) を利用することも可能です.fscanf は,C++ における fscanf と似たような働きをしますので,10 ~ 12 行目のように,strtok を使用してデータを分離する必要はありません.しかし,
      	2.3 4.5 3.4 .....					
      のように,1 行内に記述された可変個のデータを,for 文などの繰り返し文を使用して,
      	for ($i1 = 0; $i1 < $n; $i1++)
      		fscanf(STDIN, "%lf", $x[$i1]);					
      のような方法で入力した場合には,期待したとおりの結果になりませんので注意してください(改行で区切れば,問題なく動作します).

      11 行目~ 12 行目

        $str には,2 つのデータが半角スペースで区切られて入っていますので,それを分離してやる必要があります.それを実行する関数が strtok です.また,intval は,整数型に変換するための関数であり,小数点以下は切り捨てられます.

      14 行目~ 15 行目

        これらの文では,見て明らかなように,乗算と除算の計算をし,結果を変数 $mul と $div に代入しています.変数 $x,及び,$y に対しては,それらの値が参照されているだけですので,11 行目~ 12 行目で記憶された値がそのまま保たれています.入力した値,または,乗算した結果が int で表現可能な値より大きくならない,さらに,2 番目( y )の値として 0 を入力しない( 0 で割ることになる)ようにしてください.

        このプログラムを実行し,8 と 3 を,
      2つのデータを入力して下さい 8 3					
      のように入力すると(下線部が入力する部分),以下のような結果が得られます.整数型同士の除算であっても,小数点以下まで計算されることに注意してください.ただし,17 行目に対応する出力(出力の 1 行目)から明らかなように,%d を使用して出力すると小数点以下が切り捨てられます.
      乗算=24 除算=2 2.667
      乗算=24 除算=2.6666666666667
      乗算=24 除算=2.6666666666667					

    2. 関係演算子等値演算子,及び,論理演算子関係演算子,等値演算子,及び,論理演算子
      >  より大きい  a > b   式 a の値が式 b の値より大きいとき真
      <  より小さい  a < b   式 a の値が式 b の値より小さいとき真
      >= 以上     a >= b  式 a の値が式 b の値以上のとき真
      <= 以下     a <= b  式 a の値が式 b の値以下のとき真
      == 等しい     a == b  式 a の値と式 b の値が等しいとき真(配列にも使用可)
      === 等しい     a === b  式 a と式 b の型と値が等しいとき真(配列にも使用可)
      !=, <> 等しくない a != b, a <> b  式 a の値と式 b の値が等しくないとき真(配列にも使用可)
      !== 等しくない   a !== b  式 a と式 b の型か値が等しくないとき真(配列にも使用可)
      ||, or 論理和    x || y, x or y  式 x が真か,または,式 y が真のとき真
      &&, and 論理積   x && y, x and y  式 x が真で,かつ,式 y が真のとき真
      xor 排他的論理和  x xor y  式 x,または,式 y のいずれか一方だけが真のとき真
      !  否定        ! x      式 x が偽のとき真				

    3. ビット演算子シフト演算子ビット演算子とシフト演算子
      | 論理和      x | y   対応するビットのいずれかが 1 のとき真.
      & 論理積      x & y   対応するビットの双方が 1 のとき真
      ^ 排他的論理和 x ^ y   対応するビットが異なるのとき真
      ~ 1の補数     ~ x      ビット毎に 1 と 0 を反転する
      << 左にシフト   x << 3  3 ビット左にシフト.x を 23 倍することに相当.
      >> 右にシフト   x >> 3  3 ビット右にシフト.x を 23 で割ることに相当.				

    4. その他
      new: クラスのインスタンス(オブジェクト)を生成するために使用します(例: $obj = new Example() )
       + : 配列要素の追加
       & : リファレンス
       ` (実行演算子):コマンドの実行				
  4. 制御文

    1. 分岐

      • if 文
        if (論理式) {
        	文1(複数の文も可)
        }
        else {
        	文2(複数の文も可)
        }					

      • else if 文

        if (論理式) {
        	文1(複数の文も可)
        }
        else if (論理式) {
        	文2(複数の文も可)
        }
          ・・・
        else {
        	文n(複数の文も可)
        }					

      • switch 文
        switch (式) {
        	[case 定数式1 :]
        		[文1]
        	[case 定数式2 :]
        		[文2]
        	 ・・・・・
        	[default :]
        		[文n]
        }					

    2. 繰り返し

      • for 文
        for (初期設定; 繰り返し条件; 後処理) {
        	文(複数の文も可)
        }
          ・・・					

      • while 文
        while (繰り返し条件) {
        	文(複数の文も可)
        }					
      • do while 文
        do {
        	文(複数の文も可)
        } while (繰り返し条件) ;					

      • foreach 文
        foreach (配列変数名 as 値を入れる変数名) { 文 }
        foreach (配列変数名 as キーを入れる変数名 => 値を入れる変数名) { 文 }					
          配列に対する反復処理を行います.上に示した書式の通り,値だけを取り出す方法とキーと値を取り出す方法があります.この機能は,C/C++ における「範囲 for 文」と似ていますが,かなり異なった動作をします.なお,foreach は配列のコピーを取り出すため,取り出した要素の値を変更しても元の配列の値は変化しません.

  5. 配列

    1. 1 次元配列

        いくつかのデータを記憶し,それらを個々に参照したいようなとき,全てのデータに異なる名前を付けるといった方法は,データが多くなれば,非現実的です.そのような際に利用されるのが配列です.配列は,複合データ型の一種であり,複数のデータを処理する場合に利用されます.配列を作成するには,以下に示すように,配列関数の一つである array() 関数を利用します.
      01				// 宣言だけ(要素数は 0 )
      02	$x = array();   // array(3) のように要素数を指定することも可
      03	$x[0] = 1;
      04	$x[1] = 2;
      05	$x[]  = 3;
      06	print_r($x);
      07	echo "\n";
      08				// 宣言と初期設定
      09	$y = array(1, 2.3, "abc");
      10	$y[3] = 40;
      11	print_r($y);
      12	echo "\n";
      				
      (出力) 配列を見やすく表示するための関数 print_r を使用
      Array
      (
          [0] => 1
          [1] => 2
          [2] => 3
      )
      
      Array
      (
          [0] => 1
          [1] => 2.3
          [2] => abc
          [3] => 40
      )
      				

        C++ における new 演算子を使用する場合,Java,JavaScript,Python,Ruby,Ruby などにおいては,配列変数は,データを記憶している領域の先頭を指すポインタとみなすことができます.従って,配列変数 u1 を 配列変数 u2 に代入した場合,u1 と u2 は同じ場所を指すことになり,u1 を介して各要素の値を変更すれば,u2 の対応する要素の値も変化します(逆も同様).しかし,PHP においては,かなり異なっています.例えば,
      $u1 = array(1, "abc", 2);
      $u2 = $u1;				
      の最初の行で,初期設定された配列 $u1 を定義し,次の行において $u1 を $u2 に代入しています.この代入によって,$u1 のすべてのデータが $u2 にコピーされ新しい配列が作成されます.従って,$u2[1] の値を変更しても,$u1 には全く影響を与えません.

    2. 多次元配列

        多次元の配列を扱うことも可能です.例えば,
      $v1 = array(2);
      $v1[0] = array(10, 20, 30);
      $v1[1] = array(40, 50, 60);				
      のように,配列の要素を,さらに配列として定義すれば,2 次元の配列を定義できます.この例では,2 行 3 列の配列になります.2 次元配列 $v1 の i 行 j 列の要素を参照するためには,$v1[i][j] ( i : 0 ~ 1,j : 0 ~ 2 )のように記述します.

        また,1 次元配列の場合と同様,次に示す 1 行目のような記述によって,$v2 も,$v1 と同じ 2 行 3 列の配列になります.さらに,2 行目のように,2 次元配列 $v1 の各行を 1 次元配列として扱うことも可能です.いずれの場合も,1 次元配列の場合と同様,$v2 や $v3 は,$v1 の全体,または,1 行目のすべての値をコピーした全く新しい配列となり,$v2 や $v3 の値を変更しても,$v1 は全く影響を受けません.
      $v2 = $v1;
      $v3 = $v1[0];				
    3. 連想配列

        連想配列を使用することも可能です.連想配列は,以下の例に示すように,キーと値のペアで構成されます.PHP においては,通常の配列と連想配列に大きな差は無いようです.つまり,通常配列における $x[0],$x[1] などは,キーが 0,1 である連想配列として処理されているようです.
      $z = array(600, 'first'=>100, 'second'=>200, 400);
      $z[]       = 500;
      $z['last'] = 300;
      print_r($z);
      $z[1]       = 4000;
      $z['first'] = 1000;
      print_r($z);				
      (出力)
      Array
      (
          [0] => 600
          [first] => 100
          [second] => 200
          [1] => 400
          [2] => 500
          [last] => 300
      )
      Array
      (
          [0] => 600
          [first] => 1000
          [second] => 200
          [1] => 4000
          [2] => 500
          [last] => 300
      )
      				

  6. 関数

      関数は,何らかの処理を行い,その結果を返しますが,処理を行うためには外部からの情報を必要とする場合があります.ここで,引数とは,関数を呼び出した側と関数との間で,情報の受け渡しに使用される変数や定数のことです.また,関数は,計算した結果を関数を呼び出した側に戻したい場合がありますが,その際は,以下にあげるプログラム例に示すように,return 文を使用します.関数に対する一般的記述方法は,以下のようになります.

    function 関数名 (引数, ・・・) {
    	処理
    }			

      関数の引数としては,以下の例に示すように,参照渡しデフォルト引数を使用することも可能です.さらに,可変長引数もサポートしています.

      配列を引数とする場合には注意が必要です,C/C++,Java,JavaScript,Python,Ruby,Ruby などにおいては,配列変数はポインタとみなされますので,配列を関数の引数とした場合,ポインタがコピーされて渡されるため,関数内で配列の要素を変更すれば,関数を呼んだ側の対応する要素の値も変化します.しかし,PHP の場合は,配列に含まれる要素全体がコピーされて渡されるため,関数内において配列の要素の値を変更しても,関数を呼んだ側の配列はその影響を受けません.関数の呼んだ側における配列の値も変更したい場合は,参照渡しをする必要があります.ただし,次の節で述べるクラスのオブジェクトの場合は,そのアドレスが渡されるとみなされますので,関数内における変更が関数を呼んだ側に反映される点に注意してください.

    プログラム例 6.1] 関数(様々な引数)

      このプログラムでは,3 つの値(一つはデフォルト引数),配列,及び,クラスのオブジェクトを引数として渡しています.クラスに関しては,次章を参照してください.

    01	/****************************/
    02	/* 関数(様々な引数)       */
    03	/*      coded by Y.Suganuma */
    04	/****************************/
    05				// クラス Complex
    06	class Complex
    07	{
    08		public $x;
    09		public $y;
    10		function __construct($x1, $y1) {   // コンストラクタ
    11			$this->x = $x1;
    12			$this->y = $y1;
    13		}
    14	}
    15				// 関数 func
    16	function func($x1, &$x2, $y1, &$y2, $z1, $x3 = 10)
    17	{
    18		$x1   += 10;
    19		$x2   += 10;
    20		$y1[0] = 100;
    21		$y2[0] = 100;
    22		$z1->x = 1000;
    23		return ($x1 + $x2 + $x3);
    24	}
    25	
    26	$a1 = 1;
    27	$a2 = 2;
    28	$b1 = array(10, 20);
    29	$b2 = array(10, 20);
    30	$c1 = new Complex(1, 2);
    31	
    32	print "関数を呼ぶ前\n";
    33	printf("\$a1 %d \$a2 %d \$c1 %d\n", $a1, $a2, $c1->x);
    34	print_r($b1);
    35	print_r($b2);
    36	
    37	$d = func($a1, $a2, $b1, $b2, $c1);
    38	
    39	print "関数を呼んだ後\n";
    40	printf("\$a1 %d \$a2 %d \$c1 %d \$d %d\n", $a1, $a2, $c1->x, $d);
    41	print_r($b1);
    42	print_r($b2);
    			
    06 行目~ 14 行目

      クラス Complex の定義です.

    16 行目~ 24 行目

      $x1(整数,26 行目の a1 に対応), $x2(整数の参照渡し,27 行目の a2 に対応), $x3(デフォルト値を設定した整数,37 行目で引数を省略),$y1(配列,28 行目の b1 に対応), $y2(配列の参照渡し,29 行目の b2 に対応), $z1( Complex クラスのオブジェクト,30 行目の c1 に対応)を引数とした関数 func の定義です.18 行目では $x1 の値,19 行目では $x2 の値,20 行目では配列 $y1 の値,21 行目では配列 $y2 の値,また,22 行目では Complex クラスのオブジェクト z1 の値を変更しています.

    28,29 行目

      配列変数 $b1,$b2 を定義しています( 10 と 20 で初期設定).

    30 行目

      Complex クラスのオブジェクト $c1 を生成しています( 1 と 2 で初期設定).

    32 行目~ 35 行目

      関数 func を呼ぶ前の変数 $a1, $a2, $c1,$b1,$b2 を出力しています.設定したとおりの値が出力されています.

    37 行目

      5 つの変数を引数として,関数 func を呼んでいます.6 番目の変数は省略しています.

    39 行目~ 42 行目

      関数 func を呼んだ後の変数 $a1, $a2, $c1,$b1,$b2,及び,計算結果 $r を出力しています.関数を呼ぶ際,引数は,その値がコピーされて関数に渡されます.上の例では,37 行目において,各変数の値がコピーされ,16 行目の各変数に渡されます.従って,関数内において,$a1 や $b1 の値を変更( 18,20 行目)しても各変数の値は変化しません.しかし,$a2 や $b2 のように,参照渡しをすることで,関数内での変更が反映されます.しかし,変数 $c1 に関しては,参照渡しをしていないにもかかわらず,その値が変化しています.これは,C/C++ におけるアドレスを引数とした場合に相当し,関数内においてオブジェクトの値を変更すれば,関数を呼んだ側におけるオブジェクトの値も変化します.PHP は,なぜ,クラスのオブジェクトに限ってこのような仕様にしたのでしょうか.
    (出力)
    関数を呼ぶ前
    $a1 1 $a2 2 $c1 1
    Array
    (
        [0] => 10
        [1] => 20
    )
    Array
    (
        [0] => 10
        [1] => 20
    )
    関数を呼んだ後
    $a1 1 $a2 12 $c1 1000 $d 33
    Array
    (
        [0] => 10
        [1] => 20
    )
    Array
    (
        [0] => 100
        [1] => 20
    )
    			

    プログラム例 6.2] 関数(関数名)

      関数名を文字列として他の変数に代入すれば,その変数を関数として使用可能です.同様に,関数名を文字列として,関数の引数とすることも可能です.

    01	/****************************/
    02	/* 関数(関数名)           */
    03	/*      coded by Y.Suganuma */
    04	/****************************/
    05	
    06	function add($s1, $s2) {
    07		$s = $s1 + $s2;
    08		return $s;
    09	}
    10	
    11	function sub($s1, $s2) {
    12		$s = $s1 - $s2;
    13		return $s;
    14	}
    15	
    16	function add_sub($fun, $s1, $s2) {
    17		$s = $fun($s1, $s2);
    18		return $s;
    19	}
    20	
    21	printf("%d\n", add(2, 3));   // 出力: 5
    22	$kasan = "add";   // シングルクォーテーションマークでも可,以下同様
    23	printf("%d\n", $kasan(2, 3));   // 出力: 5
    24	printf("%d\n", add_sub("add", 2, 3));   // 出力: 5
    25	printf("%d\n", add_sub("sub", 2, 3));   // 出力: -1
    			
    06 行目~ 09 行目

      2 つの引数の和を計算して返す関数です.

    11 行目~ 14 行目

      2 つの引数の差を計算して返す関数です.

    16 行目~ 19 行目

      引数として渡された関数 $fun を呼び,その結果を返す関数です.

    21 行目

      関数 add を呼んでいます.

    22,23 行目

      関数名 add を,文字列として変数 $kasan に代入し,この変数を利用して関数 add を呼んでいます.このように,変数 $kasan は,関数 add と同様の働きをします.

    24,25 行目

      関数 add_sub の引数として,"add" または "sub" を渡して,いずれかの計算結果を得ています.

  7. クラス

      PHP におけるクラスの使用方法に関しては,以下に示すいくつかの例によって説明していきます.

    プログラム例 7.1] クラスと継承

    01	/****************************/
    02	/* クラスと継承             */
    03	/*      coded by Y.Suganuma */
    04	/****************************/
    05	class Number
    06	{
    07		public $name;   // var $name;
    08		protected $feat;   // var $feat;
    09		function __construct($str = "数")   // コンストラクタ
    10	//	function Number($str = "数")   // コンストラクタ
    11		{
    12			$this->name = $str;
    13			$this->feat = "数とは,・・・";
    14		}
    15		function out()
    16		{
    17			echo "Number クラスの定義です\n";
    18		}
    19	}
    20	
    21	class Complex extends Number
    22	{
    23		private $r_part;   // var $r_part;
    24		private $i_part;   // var $i_part;
    25		function __construct($x, $y, $str = "複素数")   // コンストラクタ
    26	//	function Complex($x, $y, $str = "複素数")   // コンストラクタ
    27		{
    28			parent::__construct($str);   // 親のコンストラクタ
    29	//		parent::Number($str);   // 親のコンストラクタ
    30			$this->r_part = $x;
    31			$this->i_part = $y;
    32		}
    33		function out()
    34		{
    35			echo $this->feat."\n";
    36			echo "($this->r_part, $this->i_part)\n";
    37		}
    38	}
    39	
    40	$y = new Number();
    41	echo $y->name."\n";
    42	//echo $y->feat."\n";   参照できない
    43	
    44	$x = new Complex(1.0, 2.0);
    45	echo $x->name."\n";
    46	$x->out();
    47	//echo $y->r_part."\n";   参照できない
    			
    05 行目~ 19 行目

      クラス Number の定義です.

    07,08 行目

      クラス Number のプロパティ( C/C++ におけるメンバー変数に相当)の定義です.publicprotected は,参照制限を設定するためのキーワードです.23,24 行目の private も同様です.これらのキーワードは,メソッド(クラス内の関数,C/C++ のメンバー関数に相当)にも付加することができます.public を付加されたメソッドやプロパティは,他のクラス,クラスの外,など,どこからでも参照可能です.private を付加すると,そのプロパティやメソッドが定義されているクラス内だけから参照できるようになります.なお,コメントにあるように,var キーワードを使用すると,public と同様,どこからでも参照可能となります.

      Windows のプログラムを書くような場合について考えてみてください.多くの Windows アプリケーションが存在しますが,その基本的なレイアウトや機能はほとんど同じです.それらのすべてを一から記述するとすれば大変な作業になります.しかし,Windows の基本機能を実現したプログラムがすでに存在し,そのプログラムを利用しながら必要な箇所の修正,追加を行うことによって可能であるとすれば,作業量は非常に少なくなります.これを実現したのが継承です.

      あるクラスに宣言されているプロパティやメソッドをすべて受け継ぎ(継承),受け継いだメソッドを修正,さらには,それに新たなプロパティやメソッドを付加して新しいクラスを宣言することができます.このとき,基になったクラスを親クラス,また,派生したクラスを子クラスと呼びます.

      プロパティやメソッドに対して protected 指定を行うと,そのプロパティやメソッドが定義されているクラス,及び,そのクラスの親クラス,そのクラスを継承したサブクラスだけから参照可能になります.

    09 行目~ 14 行目

      コンストラクタの定義です.コンストラクタは,そのクラスのオブジェクトが定義されたとき( 40,44 行目),最初に呼ばれるメソッドであり,初期設定等を行います.このコンストラクタの場合,デフォルト引数が設定されていますので,40 行目のように,引数 $str に対応する引数を記述しなくても,このコンストラクタが呼ばれます.なお,コンストラクタは,クラス名と同じ名前のメソッドを使用して,10 行目のようにも記述できます.

    12,13 行目

      クラスのプロパティに値を設定しています.一般に,クラスのプロパティやメソッドを参照する際は,「オブジェクト名->メソッド名」,「オブジェクト名->プロパティ名」という形で行います.ここで使用されている this は,自分自身を表すキーワードです.

    15 行目~ 18 行目

      クラス Number に所属するメソッド out( C/C++ におけるメンバー関数に相当)の定義です.

    21 行目~ 38 行目

      クラス Number を継承した クラス Complex の定義です.このように,あるクラスを継承するには,キーワード extends を使用します.

    28 行目

      あるクラスを継承しても,そのコンストラクタは継承されません.親クラスのコンストラクタで行うべき作業がある場合は,この例のように,親クラス( parent )のコンストラクタを呼んでやる必要があります.なお,親クラスのコンストラクタが,10 行目のような形で記述されている場合は,29 行目のような形で記述することも可能です.ここで,スコープ演算子( :: )は,クラス定数,スタティックプロパティ,スタティックメソッド(後述)にアクセスする際に用いられます.

    33 行目~ 37 行目

      クラス Complex に所属するメソッド out の定義です.クラス Complex のプロパティが,23,24 行目のように,private になっているため,このメソッドを使用してそれらの値を出力せざるを得ません.継承する際に,メソッドも継承されますが,15 行目~ 18 行目のままでは,ここでは役に立ちません.そこで,継承したメソッド out をオーバーライド(書き直し)しています.なお,15 行目のメソッド out の定義において,以下に示すような final 設定を行えば,サブクラスでそのメソッドをオーバーライドできなくなります.なお,プロパティに対して final 指定を行うことはできません.
    	final function out()				

    40,45 行目

      new 演算子を使用して,Number クラス,及び,Complex クラスのオブジェクトを生成しています.
    (出力)
    数
    Number クラスの定義です
    複素数
    数とは,・・・
    (1, 2)			

    プログラム例 7.2] オブジェクトの複製

    01	/****************************/
    02	/* オブジェクトの複製       */
    03	/*      coded by Y.Suganuma */
    04	/****************************/
    05	class Complex {
    06		public $r_part;
    07		public $i_part;
    08		function __construct($x, $y)
    09		{
    10			$this->r_part = $x;
    11			$this->i_part = $y;
    12		}
    13	}
    14	
    15	class Example {
    16		public $x;
    17		public $y;
    18		public $c;
    19		function __construct($x, $y)
    20		{
    21			$this->x = $x;
    22			$this->y = $y;
    23			$this->c = new Complex($this->x, $this->y);
    24		}
    25	}
    26				// 基本オブジェクト
    27	echo "    基本オブジェクト\n";
    28	$e1 = new Example(1, 2);
    29	echo '$x '.$e1->x.' $y '.$e1->y."\n";
    30	echo '$c ('.($e1->c)->r_part.', '.($e1->c)->i_part.")\n";
    31				// $e1 を $e2 に代入後,$e2->y を 20,($e2->c)->r_part を 100 に変更
    32	echo '    $e1 を $e2 に代入後,'."\n";
    33	echo '    $e2->y を 20,($e2->c)->r_part を 200 に変更'."\n";
    34	$e2 = $e1;
    35	$e2->y = 20;
    36	($e2->c)->r_part = 200;
    37	echo '$x '.$e1->x.' $y '.$e1->y."\n";
    38	echo '$c ('.($e1->c)->r_part.', '.($e1->c)->i_part.")\n";
    39				// $e1 のクローン $e3 を作成後,$e3->y を 30,($e3->c)->r_part を 300 に変更
    40	echo '    $e1 のクローン $e3 を作成後,'."\n";
    41	echo '    $e3->y を 30,($e3->c)->r_part を 300 に変更'."\n";
    42	$e3 = clone $e1;
    43	$e3->y = 30;
    44	($e3->c)->r_part = 300;
    45	echo '$x '.$e1->x.' $y '.$e1->y."\n";
    46	echo '$c ('.($e1->c)->r_part.', '.($e1->c)->i_part.")\n";
    			
    05 行目~ 13 行目

      クラス Complex の定義です.

    15 行目~ 25 行目

      クラス Example の定義です.プロパティとして,Complex クラスのオブジェクトを所有しています.

    27 行目~ 30 行目

      クラス Example のオブジェクト $e1 を生成し,その各プロパティの値を出力しています.

    32 行目~ 38 行目

      $e1 を $e2 に代入した後,$e2 のプロパティ $y の値を 20,$c のプロパティ $r_part の値を 200 に変更した後,$e1 の各プロパティの値を出力しています.その出力結果を見てください,変更したのは $e2 関係のプロパティの値にもかかわらず,$e1 の関連するプロパティの値も変化しています.通常の変数であれば,
    	$a = $b;
    	$b = 10;				
    のように,$b の値を変更しても,$a の値はその影響を受けないはずです.それは,$b の値のコピーが $a に代入されるからです.しかし,28 行目のように,new 演算子を使用してオブジェクトを生成した場合,C/C++ 風に述べれば,$e1 には,生成されたオブジェクトのアドレスが記憶されることになります.従って,34 行目の代入文によって,$a に記憶されているアドレスがコピーされて $b に代入されることになります.その結果,$a と $b は,同じオブジェクトを指すことになり,$b 内の値を変更すれば,対応する $a の値も変化することになります(逆も同様).

    40 行目~ 46 行目

      これを避ける一つの方法が,42 行目に示すように,clone を使用して,$e1 の複製クローン)を $e3 に代入することです.clone を使用すると,通常の変数の場合と同様,代入元の値がコピーされて代入先に代入されます.その結果,$e3 内の値を変更しても,$e1 はその影響を受けなくなります.しかし,出力結果の最後を見てください.Complex クラスのプロパティ $r_part の値は変化しています.これは,23 行目の操作によって,Example クラスのプロパティ $c には,Complex クラスのオブジェクトのアドレスが記憶されており,clone によってそのアドレスがコピーされて $e3 に代入されます.その結果,$e1 と $e3 は,同じ Complex クラスのオブジェクトを指すことになるからです.
    (出力)
        基本オブジェクト
    $x 1 $y 2
    $c (1, 2)
        $e1 を $e2 に代入後,
        $e2->y を 20,($e2->c)->r_part を 200 に変更
    $x 1 $y 20
    $c (200, 2)
        $e1 のクローン $e3 を作成後,
        $e3->y を 30,($e3->c)->r_part を 300 に変更
    $x 1 $y 20
    $c (300, 2)
    			

  8. 変数の有効範囲(スコープ)

    01	<?php
    02	
    03		/****************************/
    04		/* 変数の有効範囲(スコープ) */
    05		/*      coded by Y.Suganuma */
    06		/****************************/
    07		
    08		/*******************/
    09		/* クラス Example1 */
    10		/*******************/
    11		class Example1 {
    12			private $pri;
    13			protected $pro;
    14			public $pub;
    15	
    16			function Example1() {
    17				$this->pub = 1000;
    18				$this->pri = 2000;
    19				$this->pro = 3000;
    20			}
    21	
    22			function sub1() {
    23				printf("sub1 pub %d pri %d pro %d\n", $this->pub, $this->pri, $this->pro);
    24			}
    25		}
    26	
    27		/*******************/
    28		/* クラス Example2 */
    29		/*******************/
    30		class Example2 extends Example1 {
    31			function sub2() {
    32				printf("sub2 pub %d pro %d\n", $this->pub, $this->pro);
    33	//			printf("sub2 pri %d\n", $this->pri);   // 許されない
    34			}
    35		}
    36	
    37		/****************/
    38		/* main program */
    39		/****************/
    40				// ブロック
    41		$x = 10;
    42		$z = 30;
    43		if ($x > 5) {
    44			printf("block x %d\n", $x);
    45			$x = 15;
    46			$y = 20;
    47			printf("block x %d\n", $x);
    48			printf("block y %d\n", $y);
    49		}
    50		else {
    51			printf("block x %d\n", $x);
    52			$x = -15;
    53			printf("block x %d\n", $x);
    54		}
    55		sub();
    56		printf("x %d\n", $x);
    57		printf("y %d\n", $y);   // 最初の x が 1 の時は,y が未定義のためエラー
    58				// クラス
    59		$ex = new Example2();
    60		$ex->sub1();
    61		$ex->sub2();
    62		printf("public member( pub ) %d\n", $ex->pub);
    63	
    64		/************/
    65		/* 関数 sub */
    66		/************/
    67		function sub()
    68		{
    69			$x = 40;
    70			printf("   sub x %d\n", $x);
    71			global $z;
    72			printf("   sub z %d\n", $z);
    73		}
    74	
    75	?>
    			
      まず,41 行目において,変数 $x が定義され(変数 $x に値が代入され),10 で初期設定されています.この変数 $x は,この位置から main プログラムが終わる 62 行目まで有効になります.43 ~ 49 行目の if ブロック内の 44 行目において,変数 $x の値が出力されていますが,当然,その結果は,41 行目で宣言されたときの値になります.しかし,45 行目において,再び,変数 $x が宣言されていますが,PHP の場合は,C++ の場合とは異なり,41 行目で宣言された変数 $x に置き換わることになります.従って,ここで宣言された変数 $x の有効範囲は,main プログラムの終わりである 62 行目までになります.実際,56 行目における出力文では,45 行目において宣言された変数 $x の値が出力されます.同様に,46 行目で宣言された変数 $y の有効範囲も 62 行目までとなります.この例では,問題がありませんが,41 行目における変数 $x の初期値を 5 以下に設定すると,50 ~ 54 行目が実行されることになります.そのブロック内では,変数 $y が使用されていませんので,57 行目の出力文はエラーになってしまいます.変数が定義されているか否か(変数に値が代入されているか否か)の見極めが困難である場合も多いと思いますので,十分注意してください.

      55 行目において関数 sub を呼んでいます.69 行目では,変数 $x を宣言し,70 行目において,その値を出力しています.当然,69 行目の宣言を行わなければ,エラーになってしまいますし,また,69 行目の宣言によって,45 行目で宣言された $x の値が影響を受けることはありません( 56 行目に対応する出力結果参照).しかし,変数 $z は,関数 sub 内に宣言されておらず,42 行目において宣言されています.上で述べた変数 $x と同様,関数内において,main プログラムや他の関数内の変数を参照することはできません.しかし,71 行目の記述( global )によって,main プログラム内の変数を参照可能になります.このように,関数の外側で宣言された変数を関数内から参照可能にした変数をグローバル変数と呼びます.逆に,変数 $x や $y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.以上,41 ~ 57 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block x 15
    block y 20
       sub x 40
       sub z 30
    x 15
    y 20				
      次に,クラスに付いて考えてみます.11 ~ 25 行目においてクラス Example1 が定義され,30 ~ 35 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.PHP においては,クラス Example の各変数や関数のアクセス権は,そのままクラス Example2 に引き継がれます.

      59 行目において,Example2 のインスタンス $ex を生成し,60 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しています.このときは,3 つの変数の値がそのまま出力されます.しかし,61 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.ただし,この場合は,親クラス Example1 の private メンバー変数 $pri を参照することができない点に注意してください.また,62 行目のようなクラスの外側からの参照においては,pubulic メンバー変数 $pub だけを参照可能です.なお,private 指定は,同じクラス内の関数だけから,protected 指定は,同じクラス,親クラス,及び,そのクラスを継承したクラスだけから,また,public 指定は,どこからでも参照可能なことを意味します.以上,59 ~ 62 行目内の出力文によって,以下に示すような出力が得られます.
    sub1 pub 1000 pri 2000 pro 3000
    sub2 pub 1000 pro 3000
    public member( pub ) 1000				

情報学部 菅沼ホーム 目次 索引