PHP 例外処理

例外処理

PHP5から例外処理としてtry~catch構文が使えるようになりました。
PHP5.5以前はfinally句は使用できませんが、PHP5.5以降からはfinally句も指定できます。

PHP5.5以前
try {
    例外が発生するかもしれない処理;
} catch (発生するかもしれない例外の種類  変数名) {
    例外発生時の処理;
}
PHP5.5以降
try {
    例外が発生するかもしれない処理;
} catch (発生するかもしれない例外の種類  変数名) {
    例外発生時の処理;
} finally {
    例外が発生しても発生しなくても必ず行う処理。
}

例外を発生させるにはthrowキーワードを使います。
throw new ExceptionまたはExceptionのサブクラス(コンストラクタ引数);


使用例
<?php
//例外をThrowする
class MyClass {
    public function Method1() {
        $this->Method2();
    }
    
    private function Method2() {
        throw new Exception('例外が発生しました。');
    }
}

//例外をcatchする
$obj = new MyClass();
try {
    $obj->Method1();
} catch (Exception $e) {
    print($e->getMessage());
}
?>
実行結果


ExceptionクラスにはgetMessage()メソッドのほかにも以下のようなメソッドがあります。
getMessage例外メッセージ
getCode例外コード
getFile例外を発生したファイル名
getLine例外を発生した行数
getTraceバックトレース(配列)
getTraceAsStringバックトレース(文字列)


例外クラスを継承し独自の例外を作成する

Exceptionクラスまたはそのサブクラスを継承し独自の例外を作成することができます。
//独自例外クラス
class MyException extends Exception {}

//独自例外をThrowする
class MyClass {
    public function Method1() {
        $this->Method2();
    }
    
    private function Method2() {
        throw new MyException('例外が発生しました。');
    }
}

//独自例外をcatchする
$obj = new MyClass();
try {
    $obj->Method1();
} catch (MyException $e) {
    print($e->getMessage());
}


PHPにはExceptionのサブクラスとして以下のような例外が用意されています。
LogicExceptionは開発者が間違ったコードを実装したときに発生させる例外です。
たとえばあるメソッドは引数に数値を想定して作成しているのに、数値に変換できないような文字列が引数に指定されたときはLogicExceptionまたはそのサブクラスをthrowする。
RuntimeExceptionは実行時にしか発生しない例外で通常の例外です。
  • LogicException
    • BadFunctionCallException・・・未定義の関数をコールバックが参照したり、引数を指定しなかったりした場合にスローされる例外です。
      • BadMethodCallException・・・未定義のメソッドをコールバックが参照したり、引数を指定しなかったりした場合にスローされる例外です。
    • DomainException・・・定義したデータドメインに値が従わないときにスローされる例外です。
    • InvalidArgumentException・・・引数が期待値に一致しなかった場合にスローされる例外です。
    • LengthException・・・長さが無効な場合にスローされる例外です。
    • OutOfRangeException・・・無効なインデックスを要求した場合にスローされる例外です。
  • RuntimeException
    • OutOfBoundsException・・・値が有効なキーでなかった場合にスローされる例外です。
    • OverflowException・・・いっぱいになっているコンテナに要素を追加した場合にスローされる例外です。
    • RangeException・・・・プログラムの実行時に範囲エラーが発生したことを示すときにスローされる例外です。
    • UnderflowException・・・空のコンテナ上で無効な操作 (要素の削除など) を試みたときにスローされる例外です。
    • UnexpectedValueException・・・いくつかの値のセットに一致しない値であった際にスローされる例外です。

PHP インターフェース

インターフェース

インターフェースを定義するにはclassキーワードの代わりにinterfaceキーワードを使用します。
インターフェース内のメソッドは抽象メソッドになるので、メソッドの宣言だけを定義し、処理内容は定義しません。
メソッドにはabstractキーワードは付けません。
アクセス修飾子はpublicのみが指定できます。
interface インターフェース名 {
    public function メソッド名($arg1);
}

インターフェースを実装するにはimplementsキーワードを使用します。
複数のインターフェースを実装するにはインターフェース名をカンマで区切ります。
インターフェースを実装したクラスは、インターフェースに定義されているメソッドをすべてオーバーライドする必要があります。
メソッドをオーバーライドしたとき、引数はオーバーライド元のメソッドと同じにするか、省略可能な引数を追加することができます。
class クラス名 implements インターフェース名1, インターフェース名2 {
    public function メソッド名($arg1, $arg2=''){
        処理内容;
    };
}

コンストラクタもインターフェースで定義することができます。
マニュアルには「ひとつのクラスの中で、同じ名前の関数を含む 2 つのインターフェイスを 実装することはできません。あいまいさを解決できなくなるためです。」とありましたが 、実装してもエラーにはならないようです。
<?php
//インターフェース1
interface MyInterface1 {
    public function Method();
    public function Method1($value);
    public function __construct();
}
//インターフェース2
interface MyInterface2 {
    public function Method();
    public function Method2($value);
}
//インターフェースを実装したクラス
class MyClass implements MyInterface1, MyInterface2 {

    public function Method1($value, $str='') { print('Method1</br>'); }
    
    public function Method2($value, $str='') { print('Method2</br>'); }
    
    public function Method(){ print('Method</br>'); }
    
    public function __construct($str=''){}
}
//使用例
$obj = new MyClass();
$obj->Method();
$obj->Method1(1);
$obj->Method2(2);
?>
実行結果


インターフェースを継承し新たなインターフェースを作成することができます。
<?php
//親インターフェース
interface ParentInterface {
    public function Method1();
}
//子インターフェース
interface ChildInterface extends ParentInterface {
    public function Method2();
}
//親インターフェースを実装したクラス
class Class1 implements ParentInterface {

    public function Method1() { print('Method1</br>'); }
    
}
//子インターフェースを実装したクラス
class Class2 implements ChildInterface {

    public function Method1() { print('Method1</br>'); }
    
    public function Method2() { print('Method2</br>'); }
    
}
//使用例
print('-----Class1-----</br>');
$class1 = new Class1();
$class1->Method1();

print('-----Class2-----</br>');
$class2 = new Class2();
$class2->Method1();
$class2->Method2();
?>
実行結果

PHP abstract修飾子

abstract修飾子

abstract修飾子をつけることができるのはクラスとメソッドのみです。

クラスにabstract修飾子をつけると、そのクラスはインスタンス化できません。
abstractクラスにabstractメソッドを含める必要はありません。
<?php
//親クラス(抽象クラス)
abstract class ParentClass {
    public function ParentMethod(){
        print('ParentMethod</br>');
    }
}
//子クラス
class ChildClass extends ParentClass{
}>


//使用例

//ParentClassはインスタンス化できない。
//$parent = new ParentClass();

//ParentClassを継承したChildClassをインスタンス化する。
$child = new ChildClass();
$child->ParentMethod();
?>


メソッドにabstract修飾子をつけると、そのメソッドはサブクラスで必ずオーバーライドしなければなりません。
abstractメソッドを定義しているクラスはabstract修飾子をつけなければなりません。
abstractメソッドはメソッド定義だけを宣言し、処理内容は定義しません。
abstractメソッドをオーバーライドした際のアクセス修飾子は、abstractメソッドで定義した修飾子より同じか緩くする必要があります。
たとえばprotectedで定義したabstractメソッドをオーバーライドするときは、protectedまたはpublicにします。
abstractメソッドをオーバーライドしたとき、引数はabstractメソッドと同じにするか、省略可能な引数を追加することができます。

コンストラクタもabstract修飾子をつけることができます。
PHP5.4以前ではコンストラクタの引数はオーバーライド元のメソッドと違ってもよかったようですが、PHP5.4以降からは引数は同じか、省略可能な引数を追加することができます。
<?php
//親クラス(抽象クラス)
//abstractメソッドを定義しているクラスはabstract修飾子をつける
abstract class ParentClass {
    
    //abstractメソッドはメソッド定義だけを宣言し、処理内容は定義しません。
    protected abstract function AbstractMethod($value);
    
    //コンストラクタもabstractメソッドにすることができます。
    protected abstract function __construct();
}
//子クラス
class ChildClass extends ParentClass {
    //abstractメソッドをオーバーライド
    //アクセス修飾子は、abstractメソッドで定義した修飾子より同じか緩くする
    //引数はabstractメソッドと同じにするか、省略可能な引数を追加することができます
    public function AbstractMethod($value, $str='') {
    }
    
    //コンストラクタをオーバーライド
    //引数はabstractメソッドと同じにするか、省略可能な引数を追加することができます
    public function __construct($str=''){
    }
}
?>

PHP final修飾子

final修飾子

final修飾子をつけることができるのはクラスとメソッドのみです。
クラスにfinal修飾子をつけると、そのクラスは継承できません。
メソッドにfinal修飾子をつけると、そのメソッドは子クラスでオーバーライドできません。
コンストラクタ、アクセッサもメソッドの一種なのでfinal修飾子をつけることがきます。


クラスにfinal修飾子をつけると、そのクラスは継承できません。
<?php
final class ParentClass {
}
//継承するとエラーになります。
class ChildClass extends ParentClass {
}
?>

メソッドにfinal修飾子をつけると、そのメソッドは子クラスでオーバーライドできません。
<?php
class ParentClass {
    public final function Method(){}
}

class ChildClass extends ParentClass {
    //オーバーライドするとエラー
    public function Method() {}
}
?>

コンストラクタにfinal修飾子をつけると、そのコンストラクタは子クラスでオーバーライドできません。
<?php
class ParentClass {
    public final function __construct(){}
}

class ChildClass extends ParentClass {
    //オーバーライドするとエラー
    public function __construct(){}
?>


PHP 継承とオーバーライド

継承

クラスを継承するにはextendsキーワードを使用します。
多重継承はできません。
構文
class 子クラス extends 親クラス {
}


インスタンスメンバをオーバーライド

子クラスでメソッドをオーバーライドしなかった場合、親クラスのメソッドが呼び出されます。
子クラスから親クラスのメンバにアクセスするには「parent::」を利用します。

コンストラクタもメソッドと同じで、
子クラスでコンストラクタを定義しない場合は、親クラスのコンストラクタが継承されます。
子クラスでコンストラクタを定義した場合は親クラスのコンストラクタは自動で呼び出されませんので、親クラスのコンストラクタを明示的に呼び出す必要があります。
親クラスのコンストラクタを呼ばなくてもエラーにはなりません。
<?php
//親クラス
class ParentClass {
    protected $instanceField = 0;
    
    public function __construct($instanceField) {
        print('ParentClass:Construct</br>');
        $this->instanceField = $instanceField;
    }
    
    public function showInstanceField() {
        print($this->instanceField .'</br>');
    }
}
//子クラス1
//親クラスのメソッド、コンストラクタをオーバーライドしない。
class ChildClass1 extends ParentClass {
}

//子クラス2
//親クラスのメソッド、コンストラクタをオーバーライドする。
class ChildClass2 extends ParentClass {
    public function __construct() {
        print('ChildClass2:Construct</br>');
        $this->instanceField = 2;
    }
    
    public function showInstanceField() {
        print('ChildClass2:showInstanceField</br>');
        print($this->instanceField .'</br>');
    }
}
//子クラス3
//親クラスのメソッド、コンストラクタをオーバーライドし、親クラスのメソッドを利用する。
class ChildClass3 extends ParentClass {
    public function __construct() {
        print('ChildClass3:Construct</br>');
        parent::__construct(3);
    }
    
    public function showInstanceField() {
        print('ChildClass3:showInstanceField</br>');
        parent::showInstanceField();
    }
}


//使用例
print('-----子クラス1-----</br>');
$child1 = new ChildClass1(1);
$child1->showInstanceField();

print('-----子クラス2-----</br>');
$child2 = new ChildClass2();
$child2->showInstanceField();

print('-----子クラス3-----</br>');
$child3 = new ChildClass3();
$child3->showInstanceField();
?>
実行結果



スタティックメンバのオーバーロード

スタティックなメンバもインスタンスメンバと同じく、
子クラスでメソッドをオーバーライドしなかった場合、親クラスのメソッドが呼び出されます。
子クラスから親クラスのスタティックメンバにアクセスするには「parent::」を利用します。
子クラスで親クラスのメンバをオーバーライドしなかった場合は「self::」を利用することもできます。
<?php
//親クラス
class ParentClass {
 protected static $staticField = 5;
 
 public function __construct() {
  print('ParentClass:Construct</br>');
 }
 
 public static function showStaticField() {
  print(self::$staticField .'</br>');
 }
}
//子クラス1
//親クラスのスタティックメソッドをオーバーライドしない。
class ChildClass1 extends ParentClass { 
}

//子クラス2
//親クラスのスタティックメソッドをオーバーライド
//スタティック変数はオーバーライドしていないので「parent::」でも「self::」でアクセス可能。
class ChildClass2 extends ParentClass {
 public static function showStaticField() {
  print('ChildClass2:showStaticField' .'</br>');
  print(self::$staticField .'</br>');
 }
}
//子クラス3
//親クラスのスタティック変数、スタティックメソッドをオーバーライド
//「parent::」では親クラスのスタティック変数を参照し、「self::」では自クラスのスタティック変数を参照する。
class ChildClass3 extends ParentClass {
 protected static $staticField = 3;
 
 public static function showStaticField() {
     print('ChildClass3:showStaticField' .'</br>');
  print(self::$staticField .'</br>');
  print(parent::$staticField .'</br>');
 }
}


//使用例
print('-----子クラス1-----</br>');
ChildClass1::showStaticField();

print('-----子クラス2-----</br>');
ChildClass2::showStaticField();

print('-----子クラス3-----</br>');
ChildClass3::showStaticField();

?>
実行結果

PHP 定数

定数宣言

PHPでは定数を宣言する方法として、「define()」関数を使用する方法と、「const」キーワードを使用する方法があります。
どちらを使用しても定数名はすべて大文字で単語の区切りは「_(アンダーバー)」にするのがお約束です。
例:MY_CONST_VALUE
定数に指定できるデータ型はスカラー値(型がboolean, integer, double, string, NULL) のみで配列などは指定できません。


define()関数

構文
define('定数名', 定数値);

使用例
<?php
//定数名「TAX」値「0.05」を定義します。
define('TAX', 0.05);

//定数「TAX」を使用
$price = 1000;
$total = $price + ($price * TAX);
print($total);
?>
define()関数で定義した定数はスコープがグローバルになり、プログラム中のどんな場所でも使用することができます。
あちこちでdefine()関数を使用した定数を定義すると可読性が悪くなります。

define()関数は値の宣言時に演算やメソッドの戻り値が利用できます。
<?php

define('TAX1', 0.05);
//定数値に演算が使える
define('TAX2', 1 * TAX1);
//定数値にメソッドの戻り値を使える
define('TAX3', getTax('2015/01/01'));

function getTax($date) {
    //2014/04/01以前 消費税5%
    //2014/04/01以降 消費税8%
    //2015/10/01以降 消費税10%
    $dt = new DateTime($date);
    $tax = 0;
    if ($dt < new DateTime('2014/04/01')) {
        $tax = 0.05;
    } elseif (($dt >= new DateTime('2014/04/01')) && ($dt < new DateTime('2015/10/01'))) {
        $tax = 0.08;
    } elseif ($dt >= new DateTime('2015/10/01')) {
        $tax = 0.10;
    }
    return $tax;
}

//定数を使用
$price = 1000;

$total1 = $price + ($price * TAX1);
print($total1 .'</br>');

$total2 = $price + ($price * TAX2);
print($total2 .'</br>');

$total3 = $price + ($price * TAX3);
print($total3 .'</br>');

?>
実行結果


constキーワード

クラス内で定数を定義する場合はconstキーワードを使用します。
constキーワードはPHP5から利用可能です。
<?php
class Constant {
    
    const TAX1 = 0.05;
    const TAX2 = 0.08;
    
    public function showTax() {
        print(Constant::TAX1 .'</br>');
        print(self::TAX2 .'</br>');
    }
}
?>
クラスに定義されている定数を使用するサンプルです。
<?php

print(Constant::TAX1 .'</br>');

$obj = new Constant();
print($obj::TAX2 .'</br>');

print($obj->showTax());
?>
クラス内からconstキーワードで定義された定数にアクセスするには「クラス名::定数名」または「self::定数名」とします。
クラス外からアクセスするには「クラス名::定数名」とします。
インスタンス経由でアクセスすることもできます。
$obj = new Constant();
print($obj::TAX2);

constキーワードはdefine()関数と違って、定数の宣言に演算やメソッドの戻り値を利用することはできません。
たとえば以下のような定数定義はエラーになります。
//演算を使う
const TAX = 1 * 0.05;
//ほかの定数を使う
const STR1 = 'aaa';
const STR2 = STR1 .'bbb';
//もちろんほかのメソッドの戻りなんて使えない
const VALE = getHoge();
またconstキーワードにはアクセス修飾子はつけられません。
そのためクラス内だけで有効なクラス外に公開したくない定数などは定義できません。


クラス定数の使いどころ

クラス定数の有効な使い方がわからなかったのでググってみたところ定数をグルーピングする方法がありました。
define()で定義した定数です。
define('WEEKDAY_MON', 1);
define('WEEKDAY_TUE', 2);
define('WEEKDAY_WED', 3);
define('WEEKDAY_THU', 4);
define('WEEKDAY_FRI', 5);
define('WEEKDAY_SAT', 6);
define('WEEKDAY_SUN', 7);

define('RESULT_YES', 1);
define('RESULT_NO', 2);
define('RESULT_CANCEL', 3);
クラス定数で定義すると以下のようになります。
define()で定義するより可読性がいいですが、列挙子のような感じですね。
class Weekday {
    const MON = 1;
    const TUE = 2;
    const WED = 3;
    const THU = 4;
    const FRI = 5;
    const SAT = 6;
    const SUN = 7;
}

class Result {
    const YES = 1;
    const NO = 2;
    const CANCEL = 3;
}


定数を定数値と定数名のペアで管理する

定数は定数値と定数名をペアで管理したい(定数名とは別に別名も管理したい)です。

スタティックメンバを使用した方法

PHPでクラスが使えるならと、いつも使っている方法で書いてみました。
なんだかな・・・といった書き方になってしまいました(´・ω・`)
クラスの変数の初期化にnew演算子が使えない事、スタティック変数を初期化するためのスタティックコンストラクタがないことが不便ですね・・・
cd; }
    public function get_name() { return $this->name; }
    public function get_aliasName() { return $this->aliasName; }
    
    protected function __construct($cd, $name, $aliasName = '') {
        $this->cd = $cd;
        $this->name = $name;
        $this->aliasName = $aliasName;
    }
}
//曜日定数クラス
final class Weekday extends ConstBase {
    protected function __construct($cd, $name, $aliasName = '') {
        parent::__construct($cd, $name, $aliasName);
    }

    private static $MON;
    private static $TUE;
    private static $WED;
    private static $THU;
    private static $FRI;
    private static $SAT;
    private static $SUN;

    public static function MON(){
        if (is_null(self::$MON)) { self::$MON = new Weekday(1,'月曜日','月'); }
        return self::$MON;
    }
    public static function TUE(){
        if (is_null(self::$TUE)) { self::$TUE = new Weekday(2,'火曜日','火'); }
        return self::$TUE;
    }
    public static function WED(){
        if (is_null(self::$WED)) { self::$WED = new Weekday(3,'水曜日','水'); }
        return self::$WED;
    }
    public static function THU(){
        if (is_null(self::$THU)) { self::$THU = new Weekday(4,'木曜日','木'); }
        return self::$THU;
    }
    public static function FRI(){
        if (is_null(self::$FRI)) { self::$FRI = new Weekday(5,'金曜日','金'); }
        return self::$FRI;
    }
    public static function SAT(){
        if (is_null(self::$SAT)) { self::$SAT = new Weekday(6,'土曜日','土'); }
        return self::$SAT;
    }
    public static function SUN(){
        if (is_null(self::$SUN)) { self::$SUN = new Weekday(7,'日曜日','日'); }
        return self::$SUN;
    }
}
//使用例
print(Weekday::MON()->get_cd() .':' .Weekday::MON()->get_name());
?>

連想配列を使用した方法

クラスの変数に配列を指定できるので、連想配列を使ってもうちょっとシンプルにしてみました。
<?php
define('CD','Cd');
define('NAME','Name');
define('ALIAS_NAME','AliasName');

//曜日定数クラス
final class Weekday {
  public static $MON = array(CD=>1, NAME=>'月曜日', ALIAS_NAME=>'月');
  public static $TUE = array(CD=>2, NAME=>'火曜日', ALIAS_NAME=>'火');
  public static $WED = array(CD=>3, NAME=>'水曜日', ALIAS_NAME=>'水');
  public static $THU = array(CD=>4, NAME=>'木曜日', ALIAS_NAME=>'木');
  public static $FRI = array(CD=>5, NAME=>'金曜日', ALIAS_NAME=>'金');
  public static $SAT = array(CD=>6, NAME=>'土曜日', ALIAS_NAME=>'土');
  public static $SUN = array(CD=>7, NAME=>'日曜日', ALIAS_NAME=>'日');
  
  public static function getItems(){
   return array(self::$MON, self::$TUE, self::$WED, self::$THU, self::$FRI, self::$SAT, self::$SUN);
  }

}
//使用例
print (Weekday::$MON[CD] .'</br>');
print (Weekday::$TUE[NAME] .'</br>');
print (Weekday::$WED[ALIAS_NAME] .'</br>');

foreach (Weekday::getItems() as $item) {
 print( $item[CD] .':' .$item[NAME] .'</br>' );
}

?>


定数で値と名称をペアで管理することって普通にあると思うんですけど、PHPでは一般的にどうするのでしょう?
PHPerの人だれか教えてm(´・ω・`)m

PHP クラス定義 ~静的メンバ(static)~

クラス定義

スタティックメンバのサンプルとしてシングルトンパターンのクラスを定義しました。
シングルトンパターンとはクラスのインスタンスが1つしか生成されないことを保証するパターンです。
コンストラクタをprivateにし、外部からインスタンス化できないようにします。
自身のインスタンスを保持するstatic変数とその変数のゲッターをstaticで定義します。
<?php
class User {

    //スタティック変数
    private static $instance;
    
    //スタティックアクセサメソッド
    public static function get_instance() {
        if (is_null(self::$instance)) {
            self::$instance = new User();
        }
        return self::$instance;
    }
    
    
    //スタティックメソッド
    public static function createDefaultuser() {
        $defUser = self::get_instance();
        $defUser->lastName = "山本";
        $defUser->firstName = "一郎";
    }
    
    public static function changeUser(){
        $defUser = User::get_instance();
        $defUser->lastName = "山本";
        $defUser->firstName = "二郎";
    }

    
    //インスタンス変数
    private $lastName;
    private $firstName;
    
    //アクセサメソッド
    public function get_lastName() { return $this->lastName; }
    public function set_lastName($lastName) { $this->lastName = $lastName; }

    public function get_firstName() { return $this->firstName; }
    public function set_firstName($firstName) { $this->firstName = $firstName; }
    
    //コンストラクタ
    private function __construct( $lastName='名無しの', $firstName='ゴンベイ') {
        $this->lastName = $lastName;
        $this->firstName = $firstName;
    }
    
    //インスタンスメソッド
    public function showName(){
        print("私の名前は「" .$this->createName() ."」です。>/br<");
    }
    
    private function createName(){
        return " $this->lastName   $this->firstName";
    }
}
?>
クラスを使用するサンプル
<?php
User::get_instance()->showName();

User::createDefaultUser();
$user = User::get_instance();
$user->showName();

$user::changeUser();
$user->showName();
?>
実行結果


スタティック変数

初期化はリテラルあるいは定数でのみ可能です。 式で初期化することはできません。
つまり、スタティック変数を整数値や配列で初期化することはできますが、 他の変数の値や関数の返り値、オブジェクトなどで初期化することはできません。
private static $val = new Hoge(); はエラーになります。
インスタンス変数にオブジェクトを持たせたい場合、コンストラクタで初期化すればよいですが、
PHPではスタティックなコンストラクタはサポートされていないので、スタティック変数にオブジェクトを持たせたい場合は工夫が必要です。
う~ん。ちょっと不便だ。


クラス内から自クラスに定義されているスタティックメンバにアクセスする

クラス内からクラスに定義されているスタティックなメンバにアクセスするためには「クラス名::スタティックメンバ名」または「self::スタティックメンバ名」とします。
スタティック変数にアクセスするには「User::$instance」または「self::$instance」とします。(スタティック変数に「$」はいります。)
アクセッサやスタティックメソッドにアクセスするのも同様に「User::get_instance()」または「self::get_instance()」とします。


クラス外からクラスに定義されているスタティックメンバにアクセスする

クラス外からクラスに定義されているスタティックなメンバにアクセスするためには「クラス名::スタティックメンバ名」とします。
Userクラスに定義されたスタティックメソッド「createDefaultuser()」にアクセスするには
User::createDefaultuser()
とします。
インスタンス経由でもスタティックなメンバにアクセスできます。
$user = new User();
$user::changeUser();
$user->showName();

PHP クラス定義 ~基本~

クラス定義

クラスは基本的に1クラス1ファイルで定義し、ファイル名は「クラス名.class.php」とするのが一般的です。
以下に定義したUserクラスの場合、ファイル名は「User.class.php」となります。
クラス名はPascal形式(大文字で始め単語の区切りも大文字にする)です。

<?php
class User {

    //インスタンス変数
    private $lastName;
    private $firstName;
    
    //アクセサメソッド
    public function get_lastName() { return $this->lastName; }
    public function set_lastName($lastName) { $this->lastName = $lastName; }

    public function get_firstName() { return $this->firstName; }
    public function set_firstName($firstName) { $this->firstName = $firstName; }
    
    //コンストラクタ
    public function __construct( $lastName='名無しの', $firstName='ゴンベイ') {
        $this->lastName = $lastName;
        $this->firstName = $firstName;
    }
        
    //インスタンスメソッド
    public function showName(){
        print('私の名前は「' .$this->createName() .'」です。</br>');
    }
    
    private function createName(){
        return " $this->lastName   $this->firstName";
    }
    
}
?>
クラスを使用するサンプル
<?php
print('■User1</br>');
$user1 = new User();
$user1->showName();

print('■User2</br>');
$user2 = new User();
$user2->set_lastName('田中');
$user2->set_firstName('太郎');
$user2->showName();

print('■User3</br>');
$user3 = new User('山田','花子');
$user3->showName();
$user3->showFirstName();

?>
実行結果


アクセス修飾子

PHPで利用可能な修飾子は以下の3つ
  • public ・・・ どこからでもアクセス可能
  • protected ・・・ 現在のクラスとサブクラスでのみアクセス可能
  • private ・・・ 現在のクラス内部でのみアクセス可能
アクセス修飾子を省略した場合、publicとなる。


インスタンス変数

変数と同じく、変数の頭に「$」をつけ、camel形式(小文字ではじめ単語の区切りは大文字)で定義します。
初期化はリテラルあるいは定数でのみ可能です。 式で初期化することはできません。
つまり、インスタンス変数を整数値や配列で初期化することはできますが、 他の変数の値や関数の返り値、オブジェクトなどで初期化することはできません。
private $val = new Hoge(); はエラーになります。
インスタンス変数にインスタンスオブジェクトなどを持たせたい場合、コンストラクタで初期化することになります。


アクセサメソッド

セッターは「set_インスタンス変数名」、ゲッターは「get_インスタンス変数名」と命名します。


コンストラクタ

PHP4はクラス名と同名のメソッドをコンストラクタとしていました。
PHP5からは「__construct」とう名称でコンストラクタを定義するようにします。
もし「クラス名と同名のコンストラクタ」と「__construct」が存在する場合は「__construct」が優先されます。
コンストラクタは引数を指定することができますが、PHPではオーバーロード(同名のメソッドで引数が違うメソッドを複数定義すること)ができません。


デストラクタ

PHP5から使用でき「__destruct」という名称で定義します。


インスタンスメソッド

camel形式(小文字ではじめ単語の区切りを大文字にする)で定義します。


クラス内から自クラスに定義されているメンバにアクセスする

クラス内から自クラスに定義されているインスタンス変数やアクセッサ、インスタンスメソッドにアクセスするためには「$this」キーワードを使用します。
インスタンス変数にアクセスするには「$this->firstName」とします。(インスタンス変数に「$」はいりません。)
アクセッサやインスタンスメソッドにアクセスするのも同様に「$this->get_firstNmae()」とします。

※余談ですが・・・
文字列型の変数を扱う場合、値をダブルクォテーションで囲むと文字列に含まれる変数を展開してくれますが
$str = "私の名前は「$this->lastNmae $this->firstName」です。"
とすればインスタンス変数は展開されます。
でも
$str = "私の名前は「$this->get_lastNmae() $this->get_firstName()」です。"
としても、メソッドやアクセッサは展開されません。
あたりまえですけど、ちょっとできるかな~と思ってしまいました。


クラスをインスタンス化し使用する

クラスをインスタンス化するには
$変数名 = new クラス名([引数1,引数2,・・・]);
とします。

インスタンス化したメソッドなどにアクセスするには
[戻り値 = ] $変数名->メソッド名([引数1,引数2,・・・]);
とします。

PHP 関数

関数

[戻り値=] 関数名( [引数1, 引数2, ・・・])
関数名の命名規約は、すべて小文字で単語の間にアンダースコアを使用するスタイル「do_something()」と、camel形式「doSomething()」があるようです。

関数や静的メソッド、インスタンスメソッドのすべてをcamel形式で記述する方式や
インスタンスメソッドの場合はcamel形式を使用し、静的メソッドや関数はアンダースコア形式を使用するよう方式などあるようです。

私は、特に決まりがないならすべてcamel形式で書いていこうと思います。


戻り値のない関数

以下の例では関数「showString()」は、引数「$str」で指定した文字列を、引数「$count」で指定した回数だけ出力します。
<?php

function showString($str, $count) {
    for ($i=1; $i<=$count; $i++) {
        print("$str </br>");
    }
}

showString('やっほ~', 3);
?>
実行結果


戻り値のある関数

以下の例では関数「createString()」は、引数「$str」で指定した文字列を、引数「$count」で指定した回数だけ繰り返した文字列を返します。
<?php

function createString($str, $count) {
    $ret = '';
    for ($i=1; $i<=$count; $i++) {
        $ret .= "$str </br>";
    }
    return $ret;
}

$ret = createString('やっほ~', 3);
print($ret);

?>
実行結果


関数の引数を省略する

引数にデフォルト値を明記すると、その引数は省略可能になります。
省略可能な引数は、値の設定が必要な引数の後方に配置します。
以下の例では関数「showString()」は、引数「$str」で指定した文字列を、引数「$count」で指定した回数だけ出力します。
引数「$count」を省略した場合は5回出力します。
<?php

function showString($str, $count=5) {
    for ($i=1; $i<=$count; $i++) {
        print("$str </br>");
    }
}

showString('やっほ~');
?>
実行結果


PHP 繰り返し処理

for命令

for (初期化式; 条件式; 変化式){
    処理1;
}
<?php
for ($i=1; $i < 10; $i++ ) {
 print("ループ: $i <br/>");
}
?>
実行結果


foreach命令

foreacg (配列 as 変数) {
    処理1;
}

以下は配列の中身を表示するサンプルです。
<?php
$ary = array('aaa', 'bbb', 'ccc', 'ddd', 'eee');
foreach ($ary as $value) {
 print($value .'<br/>');
}
?>
実行結果



以下は連想配列の中身を表示するサンプルです。
<?php
$ary['key1'] = 'aaa';   
$ary['key2'] = 'bbb';   
$ary['key3'] = 'ccc'; 

print('■キーを出力<br/>');
foreach ($ary as $key){
 print($key .'<br/>');
}

print('■値を出力<br/>');
foreach($ary as $value) {
 print($value .'<br/>');
}

print('■キーと値を出力<br/>');
foreach($ary as $key=>$value) {
 print("キー: $key 、値: $value" .'<br/>');
}
?>
実行結果


while命令

while (条件式) {
    処理1;
}
<?php
$i = 1;
while ($i < 10 ) {
 print("ループ: $i <br/>");
    $i++;
}
?>
実行結果


do…while命令

do {
    処理1;
while (条件式);
<?php
$i = 1;
do {
 print("ループ: $i <br/>");
    $i++;
} while ($i < 10)
?>
実行結果


continue命令とbreak命令

ループをスキップするcontinue命令と、ループを中断するbreak命令ですが
オプションの引数で階層を指定することができ、ネストされたループのどのループをスキップまたは中断するかを指定できます。
引数を省略すると1が指定されたことになります。

以下の例だとネストされたループの内側をスキップします。
<?php
for ($i=1; $i<5; $i++ ) {
    for ($j=1; $j<10; $j++) {
        //$jが偶数であればスキップ、内側のループをスキップ
        if ($j % 2 == 0) {
            continue;
        }
        print("$i - $j <br/>");
    }
}
?>
実行結果


以下の例だとネストされたループの外側をスキップします。
<?php
for ($i=1; $i<5; $i++ ) {
    for ($j=1; $j<10; $j++) {
        //$jが偶数であればスキップ、外側のループをスキップ
        if ($j % 2 == 0) {
            continue 2;
        }
        print("$i - $j <br/>");
    }
}
?>
実行結果

PHP 条件分岐

if命令

if (条件) {
    処理1;
} elseif (条件) {
    処理2;
} else {
    処理3; 
}

<?php
$var = 8;

if ($var < 5) {
    print('$varは5以下です。');
} elseif ($var < 10) {
    print('$varは10以下です。');
} else {
    print('$varはいずれにも合致しません。');
}
?>
実行結果


switch命令

switch (式){
    case 値1:
        処理1;
        break;
    case 値2:
        処理2;
        break;
    case 値3:
        処理3;
        break;
    default:
        処理4;
}
<?php
$var = 'B';

switch ($var) {
    case 'A' :
        print('大変よくできました。');
        break;
    case 'B' :
        print('良くできました。');
        break;
    case 'C' :
        print('がんばりましょう');
        break;
    default :
        print('ランク外です。');
        break;
}
?>
実行結果

PHP 演算子

代数演算子

+$x + $y$xと$yの和
-$x - $y$xと$yの差
*$x * $y$xと$yの積
/$x / $y$xと$yの商
%$x % $y$xと$yで割った余り
++$x++$xの値に1を足した後$xを返す
++++$x$xを返した後に$xの値に1を足す
--$x--$xの値に1を引いた後$xを返す
----$x$xを返した後に$xの値に1を引く


代入演算子

=$x = 10$xに10を代入する
+=$x += 10$x = $x + 10と同じ
-=$x -= 10$x = $x - 10と同じ
*=$x *= 10$x = $x * 10と同じ
/=$x /= 10$x = $x / 10と同じ
%=$x %= 10$x = $x % 10と同じ
.=$x .= 'A'$x = $x . 'A'と同じ


比較演算子

==$x == $y$xと$yが等しい場合にTRUEを返す
===$x === $y$xと$yが等しく、かつ同じデータ型の場合にTRUEを返す
!=$x != $y$xと$yが等しくない場合にTRUEを返す
!==$x !== $y$xと$yが等しくなく、または同じデータ型でない場合にTRUEを返す
<$x < 10$xが10より小さい場合にTRUEを返す
>$x > 10$xが10より大きい場合にTRUEを返す
<=$x <= 10$xが10以下の場合にTRUEを返す
>=$x >= 10$xが10以上の場合にTRUEを返す
?$x > 10 ? 'OK' : 'NG'(条件式)?(式1):(式2) 条件式がTRUEの場合は式1をFALSEの場合は式2を返す

「==」は型変換を行って値が等しいかどうかをチェックします。
「===」は型変換を行わないので「==」で比較するよりパフォーマンスに優れます。
下の例だと「==」は文字列である$xが 数値に変換され、 数値としての比較を行います。
<?php
    $x = '10';
    $y = 10;
    print( ($x == $y) ? 'TRUE' : 'FALSE'); //TRUEが出力される
    print('
'); print( ($x === $y) ? 'TRUE' : 'FALSE'); //FALSEが出力される ?>


論理演算子

&&$x == 10 && $y == 10$xと$yがともにTRUEの場合にTRUEを返す
||$x == 10 || $y == 10$xまたは$yのいずれかがTRUEの場合TRUEを返す
xor$x == 10 xor $y == 10$xか$yかの どちらかがTRUEで、$xと$yがどちらもTRUEでない場合にTRUEを返す
!!$flag$flagがTRUEでない場合TRUEを返す


その他の演算子

.'aaa'.$memo文字列連結。
@@print(1/0)式の先頭に指定することでエラーメッセージを非表示にする

「@」演算子はエラー制御演算子ともいい、式の前に付けた場合、 その式により生成されたエラーメッセージは無視されます。
以下の例だと0で除算すると「Warning: Division by zero in xxx.php on line X」とエラーが発生します。
<?php
    print(1/0); 
?>
しかしprint命令の先頭に「@」をつけるとエラーメッセージが抑制され表示されなくなります。
<?php
    @print(1/0); 
?>

ちょっと愚痴

ドットネットの仕事中
次はJavaの仕事「とる」からJavaの勉強してと言われ
Javaの勉強するが仕事なし。

あいかわらずドットネットの仕事中
Androidで開発するからAndroidの勉強してと言われ
Androidの勉強をしても仕事なし。

やっぱりAndroidじゃなくてiPhoneで開発しようかなと言われ
これは聞き流すことにした。

やっぱりドットネットの仕事ばっかりで
忘れたころにJavaの仕事がやってきた。
おぼえてねぇよ・・・と思ったら少しは覚えてた。ヨカッタ

やっぱりドットネットの仕事してるけど
PHPの仕事ありそうだから勉強しといてと言われ
PHPの勉強している自分

なんだかなぁ

PHP 配列

配列(インデックスを指定しない)

インデックスを指定しないで配列を作成する方法です。
<?php
$array1 = array('aaa', 'bbb', 'ccc');
print_r($array1);
?>
または
<?php
$array1[] = 'aaa';
$array1[] = 'bbb';
$array1[] = 'ccc';
print_r($array1);
?>
実行結果


配列(インデックスを指定する)

インデックスを指定して配列を作成する方法です。
<?php
$array1 = array(0=>'aaa', 1=>'bbb', 2=>'ccc');
print_r($array1);
?>
または
<?php
$array1[0] = 'aaa';
$array1[1] = 'bbb';
$array1[2] = 'ccc';
print_r($array1);
?>
実行結果


連想配列

キーを指定して配列を作成する方法です。
<?php
$array1 = array('key1'=>'aaa', 'key2'=>'bbb', 'key3'=>'ccc');
print_r($array1);
?>
または
<?php
$array1['key1'] = 'aaa';
$array1['key2'] = 'bbb';
$array1['key3'] = 'ccc';
print_r($array1);
?>
実行結果


多次元配列

<?php
//array()を使用する方法
$array1 = array(
   array('山田', 'Yamada@mail.com'),
   array('田中', 'Tanaka@mail.com'),
   array('加藤', 'Kato@mail.com')
   );

print($array1[1][0]); //「田中」が出力
print('<br/>');
print($array1[2][1]); //「Kato@mail.com」が出力
print('<br/>');


//インデックスを指定する方法
$array2[0][0] = '山田';
$array2[0][1] = 'Yamada@mail.com';
$array2[1][0] = '田中';
$array2[1][1] = 'Tanaka@mail.com';
$array2[2][0] = '加藤';
$array2[2][1] = 'Kato@mail.com';

print($array2[1][0]); //「田中」が出力
print('<br/>');
print($array2[2][1]); //「Kato@mail.com」が出力
print('<br/>');


//キーを指定する方法
$array3[0]['name'] = '山田';
$array3[0]['mail'] = 'Yamada@mail.com';
$array3[1]['name'] = '田中';
$array3[1]['mail'] = 'Tanaka@mail.com';
$array3[2]['name'] = '加藤';
$array3[2]['mail'] = 'Kato@mail.com';

print($array3[1]['name']); //「田中」が出力
print('<br/>');
print($array3[2]['mail']); //「Kato@mail.com」が出力
print('<br/>');


//他にも
$aryName = array('山田', '田中', '加藤');
$aryMail = array('Yamada@mail.com', 'Tanaka@mail.com', 'Kato@mail.com');
$array4 = array($aryName, $aryMail);

print($array2[1][0]); //「田中」が出力
print('<br/>');
print($array2[2][1]); //「Kato@mail.com」が出力
print('<br/>');

?>
実行結果


配列の初期化

<?php
$array1 = array();
?>


配列の変更・追加

<?php
$array1[0] = 'aaa';
$array1[1] = 'bbb';
$array1[3] = 'ccc';

//変更
$array[0] = 'aaa_upd';

//追加
$array1[] = 'ddd'; //配列の途中に空き要素があっても、配列の最後(要素4)に追加される

print_r($array1);
?>


実行結果

PHP 変数

変数

PHPは変数の宣言を必要としません。
スクリプト内で変数が初めて使用されたタイミングでメモリに領域が確保されます。

変数は「$」で始まること。
変数名の大文字、小文字は区別されます。
変数の型は基本的に意識しません。
変数の命名規約はcamel形式(小文字で開始し単語の区切りを大文字にする。例:$intValue)が一般的なようです。
<?php
    $data = 'Hello';
    print($data);
    $data = 1234;
    print($data);
?>


文字列型の変数

文字列型の変数を扱う場合、値をダブルクォテーションまたはシングルクォテーションで囲む必要があります。
使い分けは文字列に含まれる変数をを展開するかどうかで区別します。
<?php
$value = 'Hello';
//シングルクォテーションは変数が展開されない
$str1 = '$value World!<br/>';
print($str1);
//ダブルクォテーションは変数が展開される
$str2 = "$value World!<br/>";
print($str2);
?>
実行結果



データ型のキャスト

PHPはデータ型にうるさくない言語ですが、キャストが必要な場合は下記のように行います。
<?php
//整数型から文字列型へのキャスト
$intvalue = 123;
$strvalue = (string)$intvalue;
print($strvalue);
?>
キャストで指定可能なデータ型
(int), (integer) - 整数へのキャスト
(bool), (boolean) - 論理値へのキャスト
(float), (double), (real) - float へのキャスト
(string) - 文字列へのキャスト
(binary) - バイナリ文字列へのキャスト (PHP 6)
(array) - 配列へのキャスト
(object) - オブジェクトへのキャスト
(unset) - NULL へのキャスト (PHP 5)

PHP 基本

PHPとは

PHPとはサーバーサイドスクリプト言語です。
HTML埋め込み型のスクリプト言語で、コンパイル不要のインタープリター言語です。


スクリプティングデリミタ

PHPはHTMLコードの中に「<?php ~ ?>」というブロックを記述し、そのブロック内にPHPの命令を記述します。
<?php

?>


コメント

1行コメントは「//」
ブロックコメントは「/* ~ */」
<?php
    //1行コメント

    /*
    ブロックコメント
    */
?>


PHPではそれぞれの式は「;(セミコロン)」で区切られます。
<?php
    print('Hello World!');

    print
    ('Hello World!');
 
?>

PHP 環境作成

Apacheの入手

http://httpd.apache.org/よりApacheをダウンロードします。
インストーラ付の2.2.22をダウンロードしました。

「Download!」より「From a Mirror」を選択します。


「archive download site」を選択します。


「binaries/」を選択します。


「win32/」を選択します。


「httpd-2.2.22-win32-x86-openssl-0.9.8t.msi」を選択します。



Apacheのインストール

先ほどダウンロードした「httpd-2.2.22-win32-x86-openssl-0.9.8t.msi」を実行しインストールを開始します。

「Next」をクリックします。


「I accept the terms int the license agreement」を選択し、「Next」をクリックします。


「Next」をクリックします。


Network Domain(サーバのドメイン名) : localhost
Server Name(wwwサーバ名) : localhost
Administrator's Email Address(管理者のメールアドレス) : aaa@bbb.com
を設定し、「for All Users, on Port80, as a Service」を選択し、「Next」をクリックします。


「Typical」を選択し、、「Next」をクリックします。


インストールフォルダを設定します。
※今回は「C:\Program Files2\Apache2.2」にインストールするので、Changeボタンからインストールフォルダを変更し、「Next」をクリックします。



「Install」をクリック します。


「Finish」をクリック します。


インストールが完了したらタスクバーに「Apache HTTP Server Monitor」が表示されます。
赤色の場合はApacheは停止しています。


このアイコンを右クリックし「Open Apache Monitor」を選択します。
Apache Service Monitorが表示されるので、「Start」ボタンをクリックし、Apacheを起動します。


緑色の場合はApacheは起動しています。


ブラウザで「http://localhost/」にアクセスし下記のようなページが表示されることを確認します。



PHPの入手

http://php.net/downloads.phpよりPHPをダウンロードします。
2013/03/01時点での最新は5.4.12

Windowsで使用するので「Windows 5.4.12 binaries and source」を選択します。


「VC9 x86 Thread Safe」の「Zip」を選択します。


ダウンロードした「php-5.4.12-Win32-VC9-x86.zip」を解凍します。
解凍したフォルダをC:\Program Files2に配置しフォルダ名を「php-5.4.12」にリネームします。

C:\Program Files2\php-5.4.12フォルダ内にある「 php.ini-development」ファイルを同フォルダにコピーし、「php.ini」にリネームします。


PHPとApacheとの連携を行う

C:\Program Files2\Apache2.2\conf\httpd.confをテキストエディタで開きます。
最終行に以下の3行を追加します。
PHPIniDir "c:/Program Files2/php-5.4.12"
LoadModule php5_module "c:/Program Files2/php-5.4.12/php5apache2_2.dll"
AddType application/x-httpd-php .php



動作確認

C:\Program Files2\Apache2.2\htdocsフォルダに「phpinfo.php」ファイルを作成します。
ファイルの内容は次のコードを記載します。
<?php phpinfo(); ?>

Apacheを再起動し、ブラウザで「http://localhost/phpinfo.php」にアクセスします。
下記のようなページが表示されたら設定は成功です。