新しいブログに移動しました。
9ensanのLifeHack
こちらの記事も必要に応じて新しいブログに移動させる予定です。
今後ともよろしくお願い致します。

HOME

PHP入門 第15回 クラスとオブジェクト

  • 2009.02.14 (土) 10:54
  • PHP

クラスとオブジェクトについて学んでいきます。

クラス

PHP5のクラスの定義は次のような書式を持っています。

1
2
3
4
5
6
7
8
9
[abstract|final] class クラス名 [extends クラス名]
{
    クラス定義の本体
}
 
[abstract|final] class クラス名 [inplements インターフェース名]
{
    クラス定義の本体
}

書式からも抽象クラス、継承、インターフェースをサポートすることが、わかります。

クラス定義の中身にはオブジェクトがもつ変数であるプロパティ、関数であるメソッドを定義します。

キーワード 説明
abstract 抽象クラスの指定
final 継承不可であることの指定
class クラス定義の開始
extends 継承元のクラス指定
implements 実装するインターフェース名の指定

 クラスとオブジェクトの利用方法の例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// クラス定義の開始
class SimpleObject {
    private $var; // このオブジェクト専用のプロパティ
 
    public function __construct($var) { // コンストラクタ
        $this->var = $var; //オブジェクトのプロパティを初期化
    }
 
    public function getVar() { //メソッド
        return $this->var;
    }
 
}
 
// クラスからインスタンス(オブジェクト)の生成
$obj = new SimpleObject('ABC');
// クラスプロパティを取得して出力
echo $obj->getVar(); // 'ABC’を出力
?>

オブジェクトを利用するには、classでクラス定義を行い、new 演算子でオブジェクトを生成します。

生成したオブジェクトのプロパティやメソッドにアクセスするには、

  • $this->var
  • $obj->getVar()

のように「->」を利用します。

$thisという変数はオブジェクト自身を表す特別な変数です。

プロパティ

オブジェクトは、プロパティと呼ばれるオブジェクト内に保持する変数を定義できます。

プロパティには、public、protected、private キーワードを使用して可視性を指定できるようになっています。

PHP4との互換性のためにvarも使用できますが、PHP5のオブジェクトではvarを使用するべきではありません。
varをPHP5で使用した場合、publicを指定したのと同じ扱いになります。

PHPのクラスのプロパティはデフォルト値を設定できます。
ただし、デフォルト値は定数である必要があります。(PHPのコンパイル時に評価できる値でないといけないからです)
なので、関数からの戻り値などは、プロパティのデフォルト値として利用できません。
(クラスが生成される時に呼び出されるメソッド、コンストラクタにて初期値を設定することができます)

1
2
3
4
5
6
7
<?php
class SimpleObject {
    public    $a;
    protected $b;
    private   $c;
}
?>

staticキーワードを使用するとオブジェクトを生成しなくてもプロパティ/メソッドを参照できるようになります。
クラスやオブジェクトのプロパティ/メソッドの参照を指定するためには、”::”スコープ解決演算子を使用します。

1
クラス名::$プロパティ名
1
2
3
4
5
6
7
<?php
class SimpleObject {
    public static $a = "static property";
}
 
echo SimpleObject::$a;
?>

クラス定義内では、クラス名にself、parentという特別なクラス名が利用できます。
self、parentは小文字でないといけません。
(PHP5から大文字、小文字を区別するようになりました)

名前 説明
self オブジェクト自身を意味するクラス名
parent 親オブジェクト(継承元)をいっみするクラス名

self、parentを使用してクラス内のプロパティ/メソッドにアクセスした場合、static宣言していない場合、エラーとなってアクセスできません。
self::文を使用してオブジェクト内のプロパティやメソッドにアクセスすることもできますが、普通オブジェクト自身のプロパティにアクセスするには、オブジェクト自身をさす特別な変数"$this”を使用します。
$thisを使用するには、オブジェクトはインスタンス(newを使って生成されたオブジェクト)でないといけません。

オブジェクト定数

値が変更できない定数をクラス内に定義することができます。
クラス内で参照する定数については、クラス外部で定義するよりもクラス内定数として定義することで、定数の意味合いが視覚的にもわかりやすくなります。
定数は、通常の変数とは異なり、定義または使用する際に $ 記号を付けません。

定義する値は定数表現である必要があり、変数・クラスのメンバー・ 演算結果あるいは関数のコールなどであってはいけません。

インターフェイスに 定数 を持たせることもできます。

1
const 定数名 = 値;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class MyClass
{
    const constant = 'constant value';
 
    function showConstant() {
        echo  self::constant . "\n";
    }
}
 
echo MyClass::constant . "\n";
 
$classname = "MyClass";
echo $classname::constant . "\n"; // PHP 5.3.0 以降で対応
 
$class = new MyClass();
$class->showConstant();
 
echo $class::constant."\n"; // PHP 5.3.0 以降で対応
?>

メソッド

メソッドとは、オブジェクトがデータ操作などに必要とする手続きを定義した関数です。

メソッドは通常の関数と同じように定義できます。

プロパティと同じようにメソッドにも可視性を指定できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
class SimpleObject {
    public    $a;
    protected $b;
    private   $c;
 
    function __construct($a, $b, $c = null) {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }
 
    public function getA() {
    	return $this->a;
    }
 
    public function getB() {
    	return $this->b;
    }
 
    public function getC() {
    	return $this->c;
    }
}
 
$obj = new SimpleObject(1, 2);
echo $obj->getA(); //「1」を出力
echo $obj->getB(); //「2」を出力
echo $obj->getC(); //出力結果なし
?>

$thisは、オブジェクト自身を参照する特別な変数です。
オブジェクト自身のプロパティやメソッドにアクセスする場合に$this変数を利用します。
$thisは特別な変数の為、上書きするとエラーが発生します。
(PHP4まではエラーは発生しません)

 特別な意味をもつメソッドが定められています。
それは、オブジェクト生成時に自動的に呼び出される関数や、オブジェクト消滅時に自動的に呼び出される関数などです。
以下に特別なメソッドの一覧になります。

メソッド名 説明
__constructor オブジェクト生成時に呼び出される関数
__destructor オブジェクト破棄時に呼び出される関数
__get 存在しないプロパティを参照しようとしたときに呼び出される関数
__set 存在しないプロパティを設定しようとしたときに呼び出される関数
__call 存在しないメソッドを呼び出した時に呼び出される関数
__wakeup unserialize関数でオブジェクトを再生成する場合に呼び出される関数
__sleep serialize関数でオブジェクトを永続化する場合にに呼び出される関数
__toString オブジェクトをprint/echoで出力する時に呼び出される関数
(文字列型にオブジェクトを変換しようとした時)
__clone cloneステートメントが呼び出された時に呼び出される関数

コンストラクタ

オブジェクトを生成する際に、オブジェクトを初期化するコードを記述するメソッドのことをコンストラクタといいます。
コンストラクタは、定義されていなくてもかまいません。

1
2
3
4
5
class クラス名 {
    void function __construct([mixed 変数 [,・・・]]) {}
}

コンストラクタの使用例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class SimpleObject {
    public $var;
 
    // コンストラクタを定義
    function __construct($var) {
        $this->var = $var;
    }
}
 
// コンストラクタに引数を渡してオブジェクトを生成
$obj = new SimpleObject('TEST');
 
echo $obj->var; // 「TEST」を出力
?>

PHP5では、___construct()をコンストラクタとして使用します。
継承を利用している場合、親クラスのコンストラクタは自動的には呼び出されません。
親クラスのコンストラクタを呼び出す為には、明示的に呼び出す必要があります。

PHP4ではクラス名と同じ名前を持つメソッドがコンストラクタとして扱われます。
PHP5でも互換性を持たせる為に、クラス名と同じメソッド名をコンストラクタとして利用できます。
ですが、__construct()をコンストラクタとして使用するほうがいいでしょう。

デストラクタ

オブジェクトが消滅する際に、自動的に呼び出されるメソッドのことをデストラクタといいます。
デストラクタは、定義されていなくてもかまいません。

1
2
3
4
5
class クラス名 {
    void function __destruct(void) {}
}

デストラクタの使用例)

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class SimpleObject {
 
    // デストラクタを定義
    function __destruct() {
    	echo __METHOD__.' is called';
    }
}
 
// オブジェクトを生成
$obj = new SimpleObject();
//「SimpleObject::__destruct is called」と出力されます。
?>

PHP5では、___destruct()をデストラクタとして使用します。
継承を利用している場合、親クラスのデストラクタは自動的には呼び出されません。
親クラスのデストラクタを呼び出す為には、明示的に呼び出す必要があります。

デストラクタは、PHP5からサポートされました、ですのでPHP4では使用することはできません。

継承

継承とは、あるクラスの機能を引き継ぎながら、既存のプロパティ/メソッドを上書きしたり、あらたなメソッドを追加することを言います。
extendsキーワードを使用することで、指定されたクラスを継承するこtが可能になります。
継承してできたクラスをサブクラス(子クラス、派生クラス)と言い、継承元のクラスのことをスーパークラス(親クラス、基底クラス)と言います。
継承の世代数に制限はありませんが、複数の親クラスからの継承(多重継承)はサポートされていません。

継承を利用することで、コードの再利用性を高めることができます。

1
2
3
class クラス名 extends 親クラス {}

 継承の使用例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
class Graphics {
	public $x, $y;
	function test() {
		$x = 1;
		$y = 1;
	}
 
	function triangle($num1, $num2) {
		$this->x = $num1;
		$this->y = $num2;
		return $this->x * $this->y /2;
	}
}
 
// Graphicsクラスを継承したGraphicsUpクラスを定義
class GraphicsUp extends Graphics {
	function square($num1, $num2) {
		$this->x = $num1;
		$this->y = $num2;
		return $this->x * $this->y;
	}
}
 
$obj = new GraphicsUp();
echo $obj->triangle(10,2); // 親クラスのtriangleメソッドを実行した結果が得られます。出力結果:「10」
echo $obj->square(10,2);   // 子クラスのsquareメソッドを実行した結果が得られます。出力結果:「20」
?>

オーバーライド

オーバーライドとは、親クラスに存在するプロパティ/メソッドと同じ名前のプロパティ/メソッドを子クラスで再定義することをいいます。
オーバーライドされたプロパティ/メソッドは明示的に親クラスのものを参照する意味をもつ「parent」を使用して参照することができます。

オーバーライドしたプロパティ/メソッドの使用例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<pre>
<?php
//親クラスの定義
class ParentObject {
	private $property = __CLASS__;
 
	public function Method() {
		echo __METHOD__."\r\n"; // 「ParentObject::Method」を出力
	}
 
	public function OtherMethod() {
		echo __METHOD__."\r\n"; // 「ParentObject::OtherMethod」を出力
	}
 
	public function GetProperty() {
		echo $this->property."\r\n";
	}
}
 
//子クラスの定義
class ChildObject extends ParentObject {
	public $property = __CLASS__;
 
	//ParentObject::Method()をオーバーライド
	public function Method() {
		echo __METHOD__."\r\n"; // 「ChildObject::Method」を出力
	}
}
 
$p = new ParentObject();
var_dump($p);
//子クラスのインスタンスを生成
$c = new ChildObject();
 
$c->Method();      // 子クラスがオーバーライドしたメソッド
$c->OtherMethod(); // オーバーライドされていない親クラスのメソッド
$c->GetProperty(); // オーバーライドされた親クラスのプロパティ
echo $c->property; // オーバーライドしたプロパティ
?>
</pre>

 実行結果)
オーバーライドのテスト

カプセル化

オブジェクト内部のプロパティを隠し、公開されたメソッドのみを利用してアクセスできるようにすることです。

Java、C++などの多くのオブジェクト指向型のプログラミング言語がもっている考え方と同様です。

キーワード 説明
public 公開されている
protected 継承したクラスのみに公開
private 非公開:同じクラス内からのみ参照可能

これらのキーワードは、クラス内のプロパティ/メソッド共に利用可能です。
メソッド宣言の可視性キーワードは省略できます。
省略した場合は、public static 宣言されたことと同等になります。

静的なプロパティとメソッド

関数に性的な変数を定義するstaticキーワードはプロパティとメソッドにも使用できます。

静的なプロパティ/メソッドとは、インスタンス(newを使用してオブジェクト生成すること)を生成しなくてもプロパティやメソッドが初期化/使用できるものの事を言います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<pre>
<?php
class SimpleObject {
	public static $cnt = 0;
 
	public static function increment() {
		self::$cnt++; // $this ではなくselfを使用しないとエラーとなる
	}
}
 
// 静的なプロパティとメソッドはインスタンスなしに利用できます。
echo SimpleObject::$cnt."\r\n"; // 0を出力
SimpleObject::increment();      // インクリメント
echo SimpleObject::$cnt."\r\n"; // 1を出力
?>
</pre>

 抽象クラス(abstract class)と抽象メソッド(abstract method)

 抽象クラスとは、インスタンスを作れないクラスです。
抽象メソッドとは中身の定義がなく、子クラスが必ず中身を定義しなければならないメソッドのことです。
abstractキーワードを利用して抽象クラス、抽象メソッドを作成できます。
抽象メソッドを持つクラスは、必ず抽象クラスとして定義されなければなりません。

抽象メソッドを持つクラスを継承したクラスは、必ず全ての抽象メソッドを実装しなければなりません。
抽象メソッドを実装するメソッドは引数の数も一致していなければなりません。

インターフェース

インターフェースとはクラスが定義すべきメソッドを指定する仕組みです。
インターフェース定義自体はメソッドが何をするのか定義する必要はありません。
クラス定義にメソッドの実装を強制する抽象クラスとにています。
抽象メソッドと同じでインターフェースで定義されているメソッドは全て実装しなければなりません。
引数の数も抽象メソッドと同じく一致している必要があります。

final宣言

通常のクラスやメソッドは、自由に拡張できますが、クラスライブラリを作成する場合、拡張を制限したい場合もあります。
クラスの継承を制限したり、メソッドのオーバーライドを制限するためにfinalキーワードが用意されています。

1
2
3
4
5
final class クラス名 { クラス定義の本体 }
final class クラス名 {
    final [public|protected|private]
        function 関数名 { 関数定義の本体 }
}

final宣言されたクラスはどのような場合でも継承元になることはできません。
final宣言されたメソッドを持つクラスは、クラス自体がfinal宣言されていなければ継承元の親クラスとなれますが、finalメソッドはオーバーライドできません。

オブジェクトの比較

オブジェクトの比較を行った場合、”==”はオブジェクト名/プロパティの値が同じか比較しTRUE/FALSEを返します。
”===”は、オブジェクトハンドルが同じ場合にのみ一致したと判断されます。
(PHP4では、”==”も”===”も判断は、オブジェクト名/プロパティの値が同じかどうかで判断されます)

オブジェクトのクローン

オブジェクトは、代入演算子"="では、コピーできません。
(オブジェクトハンドルの代入になります)
オブジェクト型のコピーを作成したい場合は、clone文を使用します。

1
2
$コピー先オブジェクト名 = clone $コピー元オブジェクト名;
$コピー先オブジェクト名 = clone($コピー元オブジェクト名);

クローンと代入演算子を使用した比較例)

1
2
3
4
5
6
7
8
9
10
11
12
<?php
 
class Object {}
 
$obj = new Object();
 
$o1 = $obj;
$o2 = clone $obj;
 
var_dump($o1 === $obj); // true
var_dump($o2 === $obj); // false
?>

オブジェクトのクローンを作成する際は、PHPはプロパティをありのままこぴーします。

例えば、オブジェクトハンドルはハンドルとしてコピーされます。
他の変数への参照も、参照のままコピーされます。
このようなコピーでは困る場合は、明示的にコピー方法を指定できます。

オブジェクトにclone文が使用された場合、__cloneメソッドが定義されていると__cloneメソッドで定義された手順でオブジェクトがコピーされます。

1
void __clone(void) { メソッド本体の定義 }

オートロード

クラス定義が行われていないクラスをインスタンス化しようとした場合、自動的にファイルを呼び込む機能
PHP5でプログラム中に未定義のクラス名があると、クラス名を引数として自動的に__autoload関数を呼び出します。

1
void function __autoload($クラス名);

__autoload関数が定義されていない場合や、__autoload関数を使用してもクラス定義が見つからない場合は、未定義のクラス名を使用されたことになり、エラーとなります。
__autoloadのエラーはcatch文でキャッチできないので、注意が必要です。

PHP入門 第14回 関数

  • 2009.02.12 (木) 08:06
  • PHP

ユーザー定義関数

関数は次のような構文で定義されます。

1
2
3
4
5
6
7
<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
    echo "関数の例\n";
    return $retval;
}
?>

 関数の中では、他の関数や クラス 定義 を含む PHP のあらゆる有効なコードを使用することができます。

関数名は、PHP の他のラベルと同じ規則に従います。
関数名として有効な 形式は、まず文字かアンダースコアで始まり、その後に任意の数の文字・ 数字・あるいはアンダースコアが続くものです。

PHP では、関数は参照される前に定義されている必要はありません。
ただし以下の二つの例のように、条件付きで関数が 定義されるような場合を除きます。

条件付きの関数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
 
$makefoo = true;
 
/* ここでは関数foo()はまだ定義されていないので
   コールすることはできません。
   しかし関数 bar()はコールできます。 */
 
bar();
 
if ($makefoo) {
  function foo()
  {
    echo "I don't exist until program execution reaches me.\n";
  }
}
 
/* ここでは $makefooがtrueと評価されているため
   安全にfoo()をコールすることができます。 */
 
if ($makefoo) foo();
 
function bar()
{
  echo "I exist immediately upon program start.\n";
}
 
?>
関数の中の関数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function foo()
{
  function bar()
  {
    echo "I don't exist until foo() is called.\n";
  }
}
 
/* ここでは関数bar()はまだ定義されていないので
   コールすることはできません。 */
 
foo();
 
/* foo()の実行によって bar()が
   定義されるためここではbar()を
   コールすることができます。*/
 
bar();
 
?>

PHP では、関数やクラスはすべてグローバルスコープです。
関数の内部で定義したものであっても関数の外部からコールできますし、 その逆も可能なのです。

PHP は関数のオーバーロードをサポートしていません。
また、宣言された関数の定義を取り消したり再定義することも できません。

オーバーロードとは、戻り値や引数の数やデータ型が異なる同名の関数やメソッドを複数定義できる機能のことです。

PHP では、関数を再帰的にコールすることが可能です。
ただし、100 から 200 を超えるような再帰呼び出しは避けてください。
そんなことをすると、 スタックが破壊され、スクリプトが異常終了してしまいます。

再帰的な関数

1
2
3
4
5
6
7
8
9
<?php
function recursion($a)
{
    if ($a < 20) {
        echo "$a\n";
        recursion($a + 1);
    }
}
?>

関数の引数

引数のリストにより関数へ情報を渡すことができます。
このリストは、カンマで区切られた式のリストです。

PHP は、値渡し(デフォルト)、 参照渡し、 デフォルト引数値  をサポートしています。
また、 可変長引数リスト  もサポートしてます。

詳しくは、 func_num_args(), func_get_arg(), func_get_args() に関する関数リファレンスを 参照ください。

使用例)

通常の関数の引数
1
2
3
4
5
6
<?php
function takes_array($input)
{
    echo "$input[0] + $input[1] = ", $input[0]+$input[1];
}
?>
参照渡しの関数の引数

(PHP5以降ではデフォルトがこの参照渡しになります。
php.iniの設定項目「allow_call_time_pass_reference」のOn/Offで参照渡しがデフォルトかどうかを制御できます。)
関数がその引 数を修正できるようにするには、その引数を参照渡しとする必要があり ます。

1
2
3
4
5
6
7
8
9
<?php
function add_some_extra(&$string)
{
    $string .= 'and something extra.';
}
$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // outputs 'This is a string, and something extra.'
?>
デフォルト引数値

関数は、スカラー引数に関して次のようにデフォルト値を 定義することができます。  
デフォルト値は、定数式である必要があり、 変数やクラスのメンバーであってはなりません。
引数のデフォルト値を使用する際には、デフォルト値を有する引数はデ フォルト値がない引数の右側に全てある必要があることに注意して下さ い。
(デフォルト値を使用したい引数の右側の引数はすべてデフォルト値が設定されていないといけないということです)

1
2
3
4
5
6
7
8
9
<?php
function makecoffee($type = "cappuccino")
{
    return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>

 戻り値

オプションの return 文により値を返すことができます。 配列やオブジェクトを含むあらゆる型を返すことができます。
これにより、関数の実行を任意の箇所で終了し、その関数を呼び出した 箇所に制御を戻すことが出来ます。

使用例)

1
2
3
4
5
6
7
<?php
function square($num)
{
    return $num * $num;
}
echo square(4);   //  '16'を出力
?>

複数の値を得る為に配列を返すこともできます

1
2
3
4
5
6
7
<?php
function small_numbers()
{
    return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
?>

関数からリファレンスを返すこともできます。
リファレンス演算子 & を関数宣 言部および変数への返り値を代入する際の両方で使用します。

1
2
3
4
5
6
7
8
<?php
function &returns_reference()
{
    return $someref;
}
 
$newref =& returns_reference();
?>

可変変数

PHP は可変関数(variable functions)の概念をサポートしています。
これにより、変数名の後に括弧が付いている場合、その値が何であろうと PHPは、同名の関数を探し実行を試みます。
この機能は、コールバック、関数テーブル等を実装するために使用可能です。

使用例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
function foo()
{
    echo "In foo()<br />\n";
}
 
function bar($arg = '')
{
    echo "In bar(); argument was '$arg'.<br />\n";
}
 
// This is a wrapper function around echo
function echoit($string)
{
    echo $string;
}
 
$func = 'foo';
$func();        // This calls foo()
 
$func = 'bar';
$func('test');  // This calls bar()
 
$func = 'echoit';
$func('test');  // This calls echoit()
?>

オブジェクトのメソッドを可変関数を使ってコールすることもできます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class Foo
{
    function Variable()
    {
        $name = 'Bar';
        $this->$name(); // Bar() メソッドのコール
    }
 
    function Bar()
    {
        echo "This is Bar";
    }
}
 
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname();  // $foo->Variable() をコールする
 
?>

 内部(ビルドイン)関数

PHPは標準で多くの関数と言語構造を持っています。
また他にも コンパイル済みの特定のPHPエクステンションを必要とする関数があります。
それらはもしコンパイルされていなければ"undefined function(未定義の関数)" として致命的エラーを発するでしょう。
例えば、 imagecreatetruecolor()のような 画像関数を使用するには、 GDサポートを有効にしてPHPをコンパイルしておく必要があります。
また、mysql_connect()を使う場合もやはり MySQLサポートを有効にしてPHPが コンパイルされている必要があります。
stringや variable関数のように どのバージョンのPHPでも含まれているコアの関数もたくさんあります。
phpinfo()やget_loaded_extensions()を コールすることで使用しているPHPにロードされているエクステンションを 見ることができます。

FCKEditorでpreタグの改行が消えてしまう原因

  • 2009.02.11 (水) 13:52
  • WordPress
  • ,

FCKEditorを使用していてpreタグの中の改行コードが消えてしまう事象が発生

これは、ある特定の場合に発生していることが判明しました

  1. IE以外のブラウザを使用している。
    (FireFoxなど)
  2. preタグの中でspanタグを使用していて、そのspanタグの中で改行コードが使用されている
    (ソースコードの整形の為のシンタックスハイライトを行っている場合に良く発生します)

この条件がそろうとFCKEditorで「ソースモード」と「WYSIWYGモード」を切り替えているとpreタグの中のspanタグの中にあった改行コードがなくなってしまいます

FCKEditorで改行コードが消える

原因を調査した結果以下のことが判明しました。

  1. FCKEditorでは、preタグ直下の要素の改行はそのまま改行と判断し、残します。
  2. preタグ以外のタグの中でbrでないただの改行コードがあった場合、半角スペースに置き換えます。

となるとpreタグの中に別のタグがあった場合、別のタグの要素として判断され改行コードを半角スペースに置き換えてしまいます。

ということは、preタグの中のspanタグの中の改行コードは、半角スペースに変更されてしまうということです。(spanタグの中の改行コードと判断される為)

なのでこれを対策する為にFCKEditorのコアファイルに修正を加えました。

修正内容)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
*** original/fckxhtml.js	2008-10-07 13:52:24.000000000 +0900
--- fckxhtml.js	2009-02-12 09:47:39.000000000 +0900
***************
*** 189,195 ****
  			// This is a workaround for the Gecko bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=92921
  			if ( FCKBrowserInfo.IsGecko
  					&& htmlNode.tagName.toLowerCase() == 'br'
! 					&& htmlNode.parentNode.tagName.toLowerCase() == 'pre' )
  			{
  				var val = '\r' ;
  				if ( htmlNode == htmlNode.parentNode.firstChild )
--- 189,199 ----
  			// This is a workaround for the Gecko bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=92921
  			if ( FCKBrowserInfo.IsGecko
  					&& htmlNode.tagName.toLowerCase() == 'br'
! 					&& (
! 						htmlNode.parentNode.tagName.toLowerCase() == 'pre' ||
! 						( htmlNode.parentNode && htmlNode.parentNode.parentNode && htmlNode.parentNode.parentNode.nodeName.IEquals( 'pre' ) )
! 					 )
! 			)
  			{
  				var val = '\r' ;
  				if ( htmlNode == htmlNode.parentNode.firstChild )
***************
*** 270,276 ****
 
  		// Text Node.
  		case 3 :
! 			if ( htmlNode.parentNode && htmlNode.parentNode.nodeName.IEquals( 'pre' ) )
  				return this._AppendTextNode( xmlNode, htmlNode.nodeValue ) ;
  			return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ;
 
--- 274,283 ----
 
  		// Text Node.
  		case 3 :
! 			if (
! 				( htmlNode.parentNode && htmlNode.parentNode.nodeName.IEquals( 'pre' ) ) ||
! 				( htmlNode.parentNode && htmlNode.parentNode.parentNode && htmlNode.parentNode.parentNode.nodeName.IEquals( 'pre' ) )
! 			 )
  				return this._AppendTextNode( xmlNode, htmlNode.nodeValue ) ;
  			return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ;

対象の要素の親の親のタグがpreかどうか判断するという方法に修正しました。
これで修正が完璧かというと完璧ではないと思います。

なのでそれぞれの環境に合うように修正して使用してください。

それでは、修正の反映方法です。

続きを見る…

PHP入門 第13回 制御構文

  • 2009.02.10 (火) 11:48
  • PHP

if

この構文は、命令の条件実行を可能にします。

1
2
if ()

使用例)
$a$b より大きい場合、aはbより大きい を表示します。

1
2
3
4
<?php
if ($a > $b)
  echo "aはbより大きい";
?>

条件分岐させたい文が一つ以上ある場合もあります。
もちろん、1文ずつ文をif 文で括る必要はありません。
代わりに、複数の文をグループ化することができます。

使用例)
$a が $b よりも大きい場合に aはbよりも大きいを表示し、 $a の値を $b に 代入します。

1
2
3
4
5
6
<?php
if ($a > $b) {
  echo "aはbより大きい";
  $b = $a;
}
?>

if文の基本的な構文とは、異なる構文もあります。
開き波括弧をコロン(:)、閉じ波括弧を endif;で記述します。

1
2
3
<?php if ($a == 5): ?>
Aは5に等しい
<?php endif; ?>

else

ある条件が満たされている場合にある文を実行し、 その条件が満たされていない場合に別の文を実行したいと考えた ことが度々あるかと思います。
このためにelseがあります。
 elseは、if文における式の値が FALSEの場合にある文を 実行するようにif文を拡張します。

使用例)
$a$bよりも大きい場合に aはbより大きいと表示し、 そうでない場合に、 aはbよりも大きくないと表示します。

1
2
3
4
5
6
7
<?php
if ($a > $b) {
  echo "aはbよりも大きい";
} else {
  echo "aはbよりも大きくない";
}
?>

elseif/else if

elseifは、その名前から分かるように、if  とelseの組み合わせです。
elseifは、 elseのように、元のif式の値が FALSEの場合に別の文を実行するようにif  文を拡張します。
しかし、elseとは異なり、elseif式が TRUEの場合にのみ代わりの式を実行します。

使用例)
aはbより大きい、 aはbに等しい、 aはbより小さいを出力します。

1
2
3
4
5
6
7
8
9
<?php
if ($a > $b) {
    echo "aはbより大きい";
} elseif ($a == $b) {
    echo "aはbと等しい";
} else {
    echo "aはbより小さい";
}
?>

while

whileループは処理を行うことができます。
whileループの構文は次のようになります。

1
2
while ()

while文は、式の値がTRUEである間、 入れ子の文を繰り返し実行することをPHPに指示します。
式の値は各反復処理の開始時にチェックされるので、ループ内の文の実行により この値が代わった場合でもループ実行は各ループを終るまで終わりません。
while式の値が初めからFALSEの 場合は、内部の文は一回も実行されません。

使用例)

1
2
3
4
5
6
7
8
<?php
$i = 1;
while ($i <= 10) {
    echo $i++;  /* 出力される値は、足される前の
                    $iの値です。
                    (後置加算) */
}
?>

 whileの異なる構文)

1
2
3
4
while ():
    文
    ...
endwhile;

do-while

do-whileループは、論理式のチェックが各反復の 最初ではなく最後に行われること以外は、whileループと 全く同じです。
通常のwhileループとの主な差は、 do-whileループは最低1回の実行を保証されていることです。

do-whileループの構文は次のようになります。

1
2
3
4
do {
    文
    ...
} while ();

 使用例)

1
2
3
4
5
6
<?php
$i = 0;
do {
    echo $i;
} while ($i > 0);
?>

for

for ループは、PHPで最も複雑なループです。
for は、Cのforループと同様に動作します。

forループの構文は、次のようになります。

1
2
for (1; 式2; 式3)

 最初の式(式1)は、ループ開始時に無条件に 評価(実行)されます。
各繰り返しの開始時に、式2が評価されます。 その式の値がTRUEが場合、ループは継続され、括弧 内の文が実行されます。値がFALSEの場合、ループの 実行は終了します。
各繰り返しの後、式3が評価(実行)されます。

各式は空にすることもできますし、複数の式をカンマで区切って指定することもできます。

式2 でカンマ区切りの式を使用すると、 すべての式を評価します。しかし、結果として取得するのは最後の式の結果となります。
式2 を空にすると、無限実行ループになります。

 使用例)
以下の例はすべて 1 から 10 までの数を表示します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
/* 例 1 */
 
for ($i = 1; $i <= 10; $i++) {
    echo $i;
}
 
/* 例 2 */
 
for ($i = 1; ; $i++) {
    if ($i > 10) {
        break;
    }
    echo $i;
}
 
/* 例 3 */
 
$i = 1;
for (; ; ) {
    if ($i > 10) {
        break;
    }
    echo $i;
    $i++;
}
 
/* 例 4 */
 
for ($i = 1, $j = 0; $i <= 10; $j += $i, print $i, $i++);
?>

 for文の異なる構文

1
2
3
4
for (1; 式2; 式3):
    文;
    ...
endfor;

foreach

 foreach文は、配列要素に関する反復処理が容易になります。
この構造には、 2種類の構文があります。
2番目の構文はあまり知られていませんが、 最初の構文の便利な拡張になっています。

foreachの構文は次のようになります。

1
2
3
4
foreach (array_expression as $value)foreach (array_expression as $key => $value)

 最初の形式は、array_expressionで指定した配列に 関してループ処理を行います。
各ループにおいて現在の要素の値が $valueに代入され、内部配列ポインタが一つ前に 進められます。

2番目の形式も同様ですが、各ループで現在の要素のキーが変数 $keyに代入されるところが異なります。

使用例)

1
2
3
4
5
6
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
}
?>

foreachの異なる構文

1
2
3
4
foreach (array_expression as $value):
    文
    ...
endforeach;

break

breakは、現在実行中の for, foreach, while, do-while, switch 構造の実行を強制的に終了します。
break では、オプションの引数で ネストしたループ構造を抜ける数を指定することができます。

 使用例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
$arr = array('one', 'two', 'three', 'four', 'stop', 'five');
while (list(, $val) = each($arr)) {
    if ($val == 'stop') {
        break;    /* ここでは、'break 1;'と書くこともできます */
    }
    echo "$val<br />n";
}
 
/* オプション引数を使用します */
 
$i = 0;
while (++$i) {
    switch ($i) {
    case 5:
        echo "At 5<br />n";
        break 1;  /* switch 構造のみを抜けます */
    case 10:
        echo "At 10; quitting<br />n";
        break 2;  /* switch と while を抜けます */
    default:
        break;
    }
}
?>

continue

continue は、ループ構造において現在の繰り返しループ の残りの処理をスキップし、条件式を評価した後に 次の繰り返しの最初から実行を続けるために使用されます。
continueでは、オプションの引数で 処理をスキップするループ構造のレベルの数を指定できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
while (list($key, $value) = each($arr)) {
    if (!($key % 2)) { // キーが偶数の組をスキップします
        continue;
    }
    do_something_odd($value);
}
 
$i = 0;
while ($i++ < 5) {
    echo "Outer<br />n";
    while (1) {
        echo "&nbsp;&nbsp;Middle<br />n";
        while (1) {
            echo "&nbsp;&nbsp;Inner<br />n";
            continue 3;
        }
        echo "This never gets output.<br />n";
    }
    echo "Neither does this.<br />n";
}
?>

swich

switch文は、同じ式を用いてIF文を並べたのに似ています。
同じ変数を異なる値と比較し、値に応じて異なったコードを実行したいと 思うことがしばしばあるかと思います。
switch
文は、まさにこのためにあるのです。

switchの構文は次のようになります。

1
2
3
4
5
6
7
8
9
10
11
swich () {
    case 値:
        文
        ...
        break;
    case 値:
        ...
    default:
        文
        ...
}

 使用例)
次の二つの例は、同じことを二つの異なった方法で書いたものです。 一つは、if文を、もう一つはswitch 文を使っています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
if ($i == 0) {
    echo "iは0に等しい";
} elseif ($i == 1) {
    echo "iは1に等しい";
} elseif ($i == 2) {
    echo "iは2に等しい";
}
 
switch ($i) {
    case 0:
        echo "iは0に等しい";
        break;
    case 1:
        echo "iは1に等しい";
        break;
    case 2:
        echo "iは2に等しい";
        break;
}
?>

 switch文を記述するときにbreakの記述を忘れると複数のcase文が実行されるので注意が必要です。
例えば、

1
2
3
4
5
6
7
8
9
10
11
<?php
$i = 0;
switch ($i) {
    case 0:
        echo "iは0に等しい";
    case 1:
        echo "iは1に等しい";
    case 2:
        echo "iは2に等しい";
}
?>

 この場合、出力結果は、「iは0に等しいiは1に等しいiは2に等しい」となります。
これは、breakがない為に複数のcase文が実行されることにより起きます。なのでひとつのcaseを実行させたい場合は必ず各caseの終わりにbreakを記述するようにしましょう。

switchの異なる構文

1
2
3
4
5
6
7
8
9
10
11
swich ():
    case 値:
        文
        ...
        break;
    case 値:
        ...
    default:
        文
        ...
endforeach;

declare

 ようわからん???だれか教えて・・・。

return

関数内で呼び出されると、return()文は即座に その関数の実行を停止し、引数を関数の値として返します。
return()はまた、eval()文や スクリプト自体の実行を終了させることが出来ます。

グローバルスコープで呼び出されると、現在実行中のスクリプトが終了 します。
もしそのスクリプトがinclude()もしくは require()されたものである場合、制御は呼び出し元 のファイルに戻ります。
また、そのスクリプトがinclude()  されたものである場合は、return()に与えられた引数 の値はinclude()の戻り値となります。

return()がメインスクリプトで呼び出された場合は スクリプトが終了します。

include

include()文は指定されたファイルを読み込み、評価します。
つまり、PHPファイルを動的に実行することができます。

include対象のファイルが存在しない場合、Warningを出力し処理を続行します。
include対象のファイルがパースエラーの場合はエラーとなり処理は中断します。

includeでのファイルの捜索範囲はphp.iniにて設定された、include_pathの値が使用されます。
ワーキングディレクトリ(getcwd()で取得できる値)から相対パスとしてinclude_pathで探します、

値の返し方: 読み込まれたファイル内では、ファイルの実行処理を終了し呼出側の スクリプトに戻るためにreturn()文を実行することが可能です。

使用例)
test.phpを実行するとinclude先のvars.phpを実行し$colorと$fruitに値を設定します。

test.php

1
2
3
4
5
6
7
8
9
<?php
 
echo "A $color $fruit"; // A
 
include 'vars.php';
 
echo "A $color $fruit"; // A green apple
 
?>

vars.php

1
2
3
4
5
6
<?php
 
$color = 'green';
$fruit = 'apple';
 
?>

require

include()  とほぼ同じですが、ファイルの読み込みに失敗した場合に Fatal Error となり致命的なエラーが発生し処理を中断します。
それ以外はincludeと同じ動作をします。

include_once

include_once()命令は、スクリプトの実行時に指定 したファイルを読み込み評価します。
この動作は、 include()命令と似ていますが、ファイルからのコー ドが既に読み込まれている場合は、再度読み込まれないという重要な違い があります。

返り値は include() と同じです。
ファイルが既に読み込まれている場合は、この関数は TRUE を返します。

require_once

require_once() 文は require() とほぼ同じ意味ですが、 ファイルがすでに読み込まれているかどうかを PHP がチェックするという点が異なります。
すでに読み込まれている場合はそのファイルを読み込みません。

goto

goto 演算子を使用すると、 プログラム中の他の命令にジャンプすることができます。
ジャンプ先はラベルとコロンで表し、 goto の後にそのラベルを指定します。

使用例)

1
2
3
4
5
6
7
<?php
goto a;
echo 'Foo';
 
a:
echo 'Bar';
?>

制御構文は、色々ありますがそれぞれ適時使えるようになると便利なので覚えておきましょう

PHP入門 第12回 演算子

  • 2009.02.09 (月) 17:57
  • PHP

PHPの演算子には、3種類あります。

  1. 単項演算子
  2. 二項演算子
  3. 三項演算子

の3つです。

単項演算子は、ひとつの値に対してのみ作用します。

二項演算子は、2つの値に対して作用します。PHPの演算子のほとんどがこの二項演算子になります。

三項演算子は、3つの値に対して作用します。実際の使用例とともに使い方を勉強しましょう。

代数演算子
意味 結果
-$a 負にする $aの符号が逆
$a + $b 加算 $a および $b の合計
$a – $b 減算 $a と $b の差
$a * $b 乗算 $a および $b の積
$a / $b 除算 $a および $b の商
$a % $b 剰余 $a を $b で割った余り
代入演算子

代入演算子の基本となるものは "=" です。

左オペランドに右オペランドの式の値を設定します。

 

1
2
3
<?php
$a = ($b = 4) + 5; // $a は 9 に等しく、$b は 4 にセットされます。
?>
ビット演算子

ビット演算子は、整数における特定のビットをオンまたはオフにすることを 可能にします。

もし左辺値と右辺値共に文字列であった場合にはビット演算子は 文字の ASCIIコードに対して作用します。

意味 結果
$a & $b ビット積 $a および $b の両方にセットされているビット
$a | $b ビット和 $a または $b のどちらかにセットされているビット
$a ^ $b 排他的論理和 $a または $b にセットされており、両方にセットされていないビット
~ $a 否定 $a にセットされているビットはセットせず、そうでないものは逆にする
$a << $b 左シフト $a のビットを左に $b ビットシフトする(各シフトは "2をかける" ことを意味します)
$a >> $b 右シフト $a のビットを右に $b ビットシフトします (各シフトは "2で割る" ことを意味します)

ビット計算を詳しく知りたい方はこちらをご覧ください。

 比較演算子
意味 結果
$a == $b 等しい $a が $b に等しい時に TRUE。
$a === $b 等しい $a が $b に等しく同じ型でである場合に TRUE
$a != $b 等しくない $a が $b に等しくない場合に TRUE。
$a <> $b 等しくない $a が $b に等しくない場合に TRUE。
$a !== $b 等しくない $a が $b と等しくないか、同じ型でない場合に TRUE
$a < $b より少ない $a が $b より少ない時に TRUE。
$a > $b より多い $a が $b より多い時に TRUE。
$a <= $b より少ないか等しい $a が $b より少ないか等しい時に TRUE。
$a >= $b より多いか等しい $a が $b より多いか等しい時に TRUE。
エラー制御演算子

PHP はエラー制御演算子(@)をサポートしています。

PHP の式の前に付けた場合、 その式により生成されたエラーメッセージは無視されます。

1
2
3
4
5
6
7
8
9
<?php
/* 意図的なエラー */
$my_file = @file ('non_existent_file') or
    die ("Failed opening file: error was '$php_errormsg'");
 
// この演算子は関数だけでなく、全ての式で動作します。
$value = @$cache[$key];
// インデックス $key が存在しない場合でも、警告を発生しません。
?>
 実行演算子

PHP は 1 種類の実行演算子、バッククォート (“) をサポートします。

シングルクォートではないことに注意してください

PHP は、バッククォートの 中身をシェルコマンドとして実行しようとします。

出力が返されます (すなわち、出力を単にダンプするのではなく、変数に代入することが できます) 。

バッククォート演算子の使用は shell_exec() と等価です。

 加算子/減算子
意味 効果
++$a 前置加算子 $a に 1 を加え、$a を返します。
$a++ 後置加算子 $a を返し、$a に1を加えます。
–$a 前置減算子 $a から 1 を引き、$a を返します。
$a– 後置減算子 $aを返し、$a から 1 を引きます。

 例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
echo "<h3>後置加算</h3>";
$a = 5;
echo "5 となります: " . $a++ . "<br>\n";
echo "6 となります: " . $a . "<br>\n";
 
echo "<h3>前置加算</h3>";
$a = 5;
echo "6 となります: " . ++$a . "<br>\n";
echo "6 となります: " . $a . "<br>\n";
 
echo "<h3>後置減算</h3>";
$a = 5;
echo "5 となります: " . $a-- . "<br>\n";
echo "4 となります: " . $a . "<br>\n";
 
echo "<h3>前置減算</h3>";
$a = 5;
echo "4 となります: " . --$a . "<br>\n";
echo "4 となります: " . $a . "<br>\n";
?>
論理演算子
意味 結果
$a and $b 論理積 $a および $b が共に TRUE の場合に TRUE
$a or $b 論理和 $a または $b のどちらかが TRUE の場合に TRUE
$a xor $b 排他的論理和 $a または $b のどちらかが TRUE でかつ両方とも TRUE でない場合に TRUE
! $a 否定 $a が TRUE でない場合 TRUE
$a && $b 論理積 $a および $b が共に TRUE の場合に TRUE
$a || $b 論理和 $a または $b のどちらかが TRUE の場合に TRUE
文字列演算子

文字列の演算子は 2 種類あります。

1つは結合演算子(‘.’)で、右引数と 左引数を結合したものを返します。

2 番目は、結合代入演算子(‘.=’)で、 この演算子は右側の引数に左側の引数を追加します。

配列演算子
意味 結果
$a + $b 結合 $a および $b を結合する。
$a == $b 同等 $a および $b のキー/値のペアが等しい場合に TRUE。
$a === $b 同一 $a および $b のキー/値のペアが等しく、その並び順が等しく、 かつデータ型も等しい場合に TRUE。
$a != $b 等しくない $a が $b と等しくない場合に TRUE。
$a <> $b 等しくない $a が $b と等しくない場合に TRUE。
$a !== $b 同一でない $a が $b と同一でない場合に TRUE。
型演算子

instanceof を使用して、 ある PHP 変数が特定の クラス  のオブジェクトのインスタンスであるかどうかを調べます。

演算子の優先順位

演算子の優先順位は、二つの式が"緊密に"結合している度合いを指定します。

1 + 5 * 3 の答えは 16 になり、18 とはなりません。

これは乗算演算子("*")は、加算演算子("+")より高い優先順位を有するか らです。

必要に応じて強制的に優先順位を設定するために括弧を使用する ことが可能です。

例えば、18と評価するためには、 (1 + 5) * 3 とします。 演算子の優先順位が等しい場合は、左から右へ順に評価されます。

結合時の評価 演算子
結合しない clone new
left [
結合しない ++ –
結合しない ~ – (int) (float) (string) (array) (object) (bool) @
結合しない instanceof
right !
left * / %
left + – .
left << >>
結合しない < <= > >= <>
結合しない == != === !==
left &
left ^
left |
left &&
left ||
left ? :
right = += -= *= /= .= %= &= |= ^= <<= >>=
left and
left xor
left or
left ,
 三項演算子

特殊な演算子で

1
1 ? 式2 : 式3;

の形で使用されます。

使用例から見ていきましょう。

例えばある変数が「5以上の場合は、10を4以下の場合は0を変数に設定する」というような条件文があったとします。

普通if文を使用して

1
2
3
4
5
if ($a >= 5) {
    $a = 10;
} else {
    $a = 0;
}

のような記述します。

しかし、三項演算子を使用すると以下のように書き換えることができます。

1
$a = $a >= 5 ? 10 : 0;

つまり

式1が条件で、その条件がTRUEの場合は、式2の値が設定され、FALSEの場合は式3の値が設定されるのが三項演算子なのです。

お薦めのレンタルサーバー
広告
お薦めの書籍
HOME