// 沒有 namespane,也就是 java 的 package
// 單一繼承,多重實做
class Book extends Publication implements Printable {
// 三種修飾子:
// private - 同一個 class
// protected - 同一個 class 與子 class
// public - 所有 class
private $author;
// 使用 static 定義 static property
public static $TYPE = 'B';
// 傳入參數可以指定型別,也可以不指定
public function __construct($title, Author $author) {
// 不像 java 會自動呼叫 parent 的 constructor,得手動呼叫,也就是說也可以不用呼叫
// 呼叫 parent 的 properties 或者 methods 都得用兩個冒號,不是用「->」
parent::__construct($title);
$this->author = $author;
}
// 像是 Java finalize,當 PHP 執行結束或者物件被 unset 時,系統自動呼叫
public function __destruct() { }
// final 同 Java final,可以用在 class 或者 method 上
public final function getBookTitle() {
// 可以存取繼承來的 parent protected property
return "[Book]$this->title";
}
public function getPublicationTitle() {
// 使用兩個冒號呼叫 parent class 的 method
return '[Publication]'.parent::getTitle();
}
// 使用 static 定義 static method
public static function getType() {
// 使用 parent 呼叫 parent class
// 使用兩個冒號呼叫 static properties,不管是 parent 或自身的
// 使用 self 呼叫自身的 static properties
return parent::$TYPE.'/'.self::$TYPE;
}
public function getAuthor() {
return $this->author;
}
// 因為 PHP 不支援 Java 的 Overloading,就是多個同名 method,但參數不同
// 但是 PHP 支援不定型別參數,所以可以藉此實做 Overloading
public static function printEverything($everything) {
if (is_scalar($everything)) {
if (is_string($everything)) {
$var = '[string]'.$everything;
}
else if (is_int($everything)) {
$var = '[int]'.(string) $everything;
}
else if (is_float($everything)) {
$var = '[float]'.(string) $everything;
}
else if (is_bool($everything)) {
$var = '[boolean]'.(string) $everything;
}
else {
$var = '[unknown scalar]';
}
}
else if (is_array($everything)) {
$var = '[array]'.implode(',', $everything);
}
else if (is_object($everything)) {
$var = '[Object]'.(string) $everything;
}
else {
$var = '[unknown type]';
}
return $var;
}
// 一定要實做繼承來的 abstract method
public function printOut() { }
// 同 Java 的 toString()
// 像 __construct 一樣,內建的 method 都是雙底線開頭
public function __toString() {
// 一定要回傳 string,不確定型別時,可以用(string)轉型
return (string) $this->title;
}
// 若要做深層克隆,得實做這個 method
public function __clone() {
// 預設會傳一個淺層克隆物件進來,就是 $this
// 只要再克隆必要的物件就可以達成深層克隆了
// 只要有定義 __clone(),克隆是會無限遞迴呼叫下去的
$this->author = clone $this->author;
}
// serialize() 時系統呼叫
public function __sleep() {
// 指定要 serialize 的屬性
// 因為同一個物件可以被 serialize 多次,且 serialize 之後仍可使用
// 所以__sleep() 裡不可做出影響物件狀態的動作
// 僅用於排除不想 serialize 的屬性
return array('title');
}
// unserialize() 時系統呼叫
public function __wakeUp() {
// 回復未被 serialize 的屬性,如資料庫連線或開啟的檔案之類的
}
}
// abstract class
abstract class Publication {
// child class 可以存取的 property
protected $title;
// 使用 static 定義 static property
public static $TYPE = 'P';
// constructor 使用固定的名字,注意是兩個底線,而且只能有一個 constructor
public function __construct($title) {
// 使用 $this 與「->」存取自身 properties 與 methods
// 「$」用在 this 上,properties 不用再加,$this->$title 的「$title」是動態參數
$this->title = $title;
}
public function setTitle($title) {
$this->title = $title;
}
public function getTitle() {
return $this->title;
}
// abstract method 不可以是 private 或者 final
abstract function __toString();
}
interface Printable {
function printOut();
}
class Author {
private $name;
public function getName() {
return $this->name;
}
public function setName($name) {
$this->name = $name;
}
}
// 若無 constructor 或 constructor 不需參數,可以不用加小括弧
// classs name 不分大小寫
$author = new author;
$author->setName('Neil');
$book = new Book("Java Artisan", $author);
// 呼叫繼承來的 parent public method
print 'Title: '.$book->getTitle().'<br/>';
// 使用大括弧在雙引號裡使用複雜的變數整合
print "Book Title: {$book->getBookTitle()}<br/>";
print "Publication Title: {$book->getPublicationTitle()}<br/>";
// 使用兩個冒號呼叫 static method
print 'Type: '.Book::getType().'<br/>';
// 呼叫__toStringt()
print "Book: $book<br/>";
// 物件是 Pass By Reference
$b = $book;
$b->setTitle('Java Artisan in PHP');
print 'New Title: '.$book->getTitle().'<br/>';
print 'New Title: '.$b->getTitle().'<br/>';
// 克隆 - 預設是淺層克隆,物件 properties 是 copy by reference,物件以外的 properties 是 copy by value
// 物件以外指的是:字串、數值、日期、陣列、布林
$c = clone $book;
$c->getAuthor()->setName('Neil Chan');
print 'Old Name: '.$book->getAuthor()->getName().'<br/>';
print 'Clone Name: '.$c->getAuthor()->getName().'<br/>';
// 用 instanceof 檢查物件型別
print 'This is '.($book instanceof Book ? 'a book!' : 'not a book!').'<br/>';
print 'This is '.($book instanceof Publication ? 'a publication!' : 'not a publication!').'<br/>';
print 'This is '.($book instanceof Printable ? 'printable!' : 'not printable!').'<br/>';
// 用 class_implements 檢查實做 interfaces
$interfaces = class_implements('Book');
print 'This is '.(isset($interfaces['Printable']) ? 'printable!' : 'not printable!').'<br/>';
print 'The Book class implements '.implode(',', $interfaces).'.<br/>';
// 用 Reflection 檢查實做 interfaces
$rc = new ReflectionClass('Book');
print 'This is '.($rc->implementsInterface('Printable') ? 'printable!' : 'not printable!').'<br/>';
// 使用不定型別實做 Overloading
print 'String: '.Book::printEverything('string').'<br/>';
print 'Boolean: '.Book::printEverything(false).'<br/>';
print 'Integer: '.Book::printEverything(123).'<br/>';
print 'Float: '.Book::printEverything(12.3).'<br/>';
print 'Array: '.Book::printEverything(array('a','b')).'<br/>';
print 'Object: '.Book::printEverything($b).'<br/>';
// 看透整個物件
print 'var_dump: <br/>';
var_dump($book);
print '<br/>';
print 'var_export: <br/>';
var_export($book);
print '<br/>';
print 'print_r: <br/>';
print_r($book);
print '<br/>';
2012-05-28
Java 腦袋學 PHP OOP
PHP Object-oriented programming 在 5 以後的版本增強不少,對 Java 腦袋來說已經很接近了,尤其 OOP 用的 keyword 幾乎和 Java 的一樣,最大的闕漏在還沒有 package。
沒有留言:
張貼留言