Last active
July 16, 2018 14:41
-
-
Save MilesChou/6008841 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* class 教學 | |
* | |
* class 全域需注意的重點: | |
* 1.全域:跟function一樣,一經宣告後,任何地方皆可使用。 | |
* 2.不可重載:跟function一樣,一經宣告後,不可再宣告同名的class | |
* | |
* 建立class的重點: | |
* 1.實例化:class宣告後,需使用new建立物件才可使用,$obj = new className(); | |
* 2.屬性(property):可以說是類別的變數,可用 $obj->property 來取得,可以設定預設值,但必需是常數。 | |
* 3.方法(method):可以說是類別的function,可用 $obj->method() 來呼叫。 | |
* 4.偽變量:物件外要取用物件內的屬性或方法時要使用$obj->property或$obj->method(),物件內要取用同一物件內的屬性或方法時要用關鍵字$this->property或$this->method() | |
* 5.建構方法:__construct()或與類別同名,在使用new的時候會執行的方法。 | |
* 6.建構方法:__destruct(),物件被unset或程式結束時會執行的方法。 | |
* 7.能見度:要設定屬性和方法前可以加上能見度的關鍵字:public任何地方都可以使用,protected父類或子類才可使用,private只有該物件本身才可使用。 | |
* 8.繼承(inheriance):使用extends關鍵字,只能單一繼承。 | |
* 9.覆寫(overriding):子類別可以覆寫父類別的方法。 | |
* 10.final:禁止類別繼承或方法覆寫。 | |
* 11.複製:使用$objB = $objA;時是複製指標,要完整複製一個新的物件要使用clone關鍵字:$objB = clone $objA; | |
* 12.靜態屬性和方法:屬性和方法前加上static,使用時不需建立物件(new)即可使用 | |
* 類別內呼叫屬性使用self::$property; 呼叫方法使用self::method(); | |
* 類別外呼叫屬性使用className::$property; 呼叫方法使用className::method(); | |
* 13.常數:定義固定值,設定方法:const MESSAGE = 'Hello'; 類別內使用self::MESSAGE;類別外使用className::MESSAGE; | |
* 14.抽象類:類別加上abstract關鍵字就不能被實例化,必需要被繼承後才能實例化。 | |
* 抽象類中方法被宣告為abstract時,就不需要實作該方法,但被繼承的類別必需要實作該方法 | |
* 15.屬性多載:__get()與__set(), 如果程式呼叫到未定義的屬性時使用 | |
* 16.方法多載:__call(), 如果程式呼叫到未定義的方法時使用 | |
* 17.建構子多載:__clone()搭配clone(deepcopy使用) | |
* 18.類別多載:如果程式呼叫到未定義的類別時, 會自動執行__autoload()方法 | |
* 19.顯示物件:__toString(), 在類別中實作此方法後, 使用echo或print顯示物件時, 會呼叫__toString()方法 | |
*/ | |
// 懶得加換行語法,做個function自動加 | |
function output($str) | |
{ | |
return $str . '<br/>'; | |
} | |
// 宣告class1 | |
class class1 | |
{ | |
// 屬性 | |
public $name; | |
// 取得name屬性的方法 | |
public function getName() | |
{ | |
// 使用偽變量來存取屬性 | |
return $this->name; | |
} | |
// 設定name屬性的方法 | |
public function setName($var) | |
{ | |
$this->name = $var; | |
} | |
} | |
// 實例化 | |
$obj = new class1(); | |
// 設定屬性 | |
$obj->name = '我的第一個Class!'; | |
// 呼叫方法 | |
echo output($obj->getName()); | |
class class2 | |
{ | |
// 私有屬性 | |
private $name = '我是class2的預設值'; | |
// 私有屬性外部不能存取 所以必需要有公開方法來存取 | |
public function setName($var) | |
{ | |
$this->name = $var; | |
} | |
public function getName() | |
{ | |
return $this->name; | |
} | |
} | |
// 實例化 | |
$obj = new class2(); | |
// 預設值 | |
echo output($obj->getName()); | |
// 設定屬性 | |
// $obj2->name = '我的第二個Class!'; >> 這樣會有錯誤 必需使用setName() | |
$obj->setName('我的第二個Class!'); | |
// 呼叫方法 | |
echo output($obj->getName()); | |
class class3 | |
{ | |
private $name; | |
// 建構方法 | |
public function __construct($var) | |
{ | |
// 使用同類別裡的setName方法 | |
$this->setName($var); | |
} | |
public function setName($var) | |
{ | |
$this->name = $var; | |
} | |
public function getName() | |
{ | |
return $this->name; | |
} | |
} | |
// 實例化同時可以執行建構方法 | |
$obj = new class3('我的第三個Class!'); | |
// 並直接輸出 | |
echo output($obj->getName()); | |
class class4 | |
{ | |
private $instance; | |
private $name = '我是第四個Class哦!'; | |
// 建構方法,參數是物件 | |
public function __construct($instance) | |
{ | |
$this->instance = $instance; | |
} | |
// 取得屬性(物件)的getName方法 | |
public function getInstanceName() | |
{ | |
return $this->instance->getName(); | |
} | |
public function setName($var) | |
{ | |
$this->name = $var; | |
} | |
public function getName() | |
{ | |
return $this->name; | |
} | |
} | |
// 參數為剛剛class3建立的物件 | |
$obj = new class4($obj); | |
// 輸出class3物件的getName方法 | |
echo output($obj->getInstanceName()); | |
// 輸出class4 getName方法 | |
echo output($obj->getName()); | |
// 進階應用的例子,使用到了設計模式中的工廠模式 | |
class class5 | |
{ | |
private $instances = array(); | |
private $name = '我是第五個Class!'; | |
// 設定實例的方法 | |
public function setInstance($class, $param = 'class5的預設參數') | |
{ | |
$this->instances[$class] = new $class($param); | |
} | |
// 呼叫實例設定名字的方法 | |
public function setInstanceName($class, $var) | |
{ | |
return $this->instances[$class]->setName($var); | |
} | |
// 呼叫實例取得名字的方法 | |
public function getInstanceName($class) | |
{ | |
return $this->instances[$class]->getName(); | |
} | |
public function setName($var) | |
{ | |
$this->name = $var; | |
} | |
public function getName() | |
{ | |
return $this->name; | |
} | |
} | |
$obj = new class5(); | |
$obj->setInstance('class1'); | |
$obj->setInstance('class2'); | |
$obj->setInstance('class3', '被class5建立的class3'); | |
$obj->setInstance('class4'); | |
$obj->setInstance('class5'); | |
$obj->setInstanceName('class1', '被class5設定name的class1'); | |
echo output($obj->getInstanceName('class3')); | |
echo output($obj->getInstanceName('class1')); | |
echo output($obj->getInstanceName('class2')); | |
echo output($obj->getInstanceName('class4')); | |
echo output($obj->getInstanceName('class5')); | |
// 跟class1相同 不過改成靜態方法 | |
class class6 | |
{ | |
// 屬性 | |
static public $name; | |
// 取得name屬性的方法 | |
static public function getName() | |
{ | |
// 使用偽變量來存取屬性 | |
return self::$name; | |
} | |
// 設定name屬性的方法 | |
static public function setName($var) | |
{ | |
self::$name = $var; | |
} | |
} | |
// $obj = new class1(); >> 不需實例化 | |
// $obj->name = '我的第一個Class!'; >> 設定屬性的方法需要改變 | |
class6::$name = '我的第六個Class!'; | |
// echo output($obj->getName()); >> 呼叫方法也要改變 | |
echo output(class6::getName()); | |
// 繼承(inheriance) | |
class class7 extends class2 | |
{ | |
private $age; | |
public function setAge($var) | |
{ | |
$this->age = $var; | |
} | |
public function getAge() | |
{ | |
return $this->age; | |
} | |
// 使用父類別的getName(); | |
public function output() | |
{ | |
return '我叫' . $this->getName() . ',今年' . $this->getAge() . '歲'; | |
} | |
} | |
$obj = new class7(); | |
// 使用父類別的setName(); | |
$obj->setName('QQ'); | |
$obj->setAge(22); | |
echo output($obj->output()); | |
// 覆寫(overriding) | |
class class8 extends class7 | |
{ | |
private $height; | |
public function setHeight($var) | |
{ | |
$this->height = $var; | |
} | |
public function getHeight() | |
{ | |
return $this->height; | |
} | |
// 覆寫顯示的方式,並設定繼承class8的class不可覆寫這個方法 | |
public final function output() | |
{ | |
return '我今年' . $this->getAge() . '歲,名字叫' . $this->getName() . ',身高' . $this->getHeight(); | |
} | |
} | |
$obj = new class8(); | |
$obj->setName('大方'); | |
$obj->setAge(18); | |
$obj->setHeight(180); | |
echo output($obj->output()); | |
// 抽象類 | |
abstract class class9 | |
{ | |
private $name; | |
public function setName($var) | |
{ | |
$this->name = $var; | |
} | |
public function getName() | |
{ | |
return $this->name; | |
} | |
// 宣告抽象類的方法不需實作 | |
abstract public function output(); | |
} | |
// $obj = new class9(); >> 抽象類不可實例化 | |
// 繼承抽象類class9 | |
class class10 extends class9 | |
{ | |
// 繼承抽象類的類別必需實作抽象類裡的抽象方法 | |
public function output() | |
{ | |
return '我是class10實作出來的方法,我名字叫"' . $this->getName() .'"'; | |
} | |
} | |
$obj = new class10(); | |
$obj->setName('叫我class10'); | |
echo output($obj->output()); | |
// 繼承抽象類class9 | |
class class11 extends class9 | |
{ | |
// 繼承抽象類的類別必需實作抽象類裡的抽象方法 | |
public function output() | |
{ | |
return '我名字叫"' . $this->getName() . '",我是class11實作出來的方法'; | |
} | |
} | |
$obj = new class11(); | |
$obj->setName('class11萬歲'); | |
echo output($obj->output()); | |
// 多載說明太麻煩了跳過 | |
// __toString方法和常數一起講,懶得打程式碼了 | |
class class12 | |
{ | |
//設定常數 | |
const STR = '我的名字叫'; | |
private $name = 'class12'; | |
// 實作後,物件可以直接轉換成字串,會依這個方法回傳值而定 | |
public function __toString() | |
{ | |
return self::STR . $this->name; | |
} | |
public function setName($var) | |
{ | |
$this->name = $var; | |
} | |
public function getName() | |
{ | |
return $this->name; | |
} | |
} | |
// 常數取用不需實例化 | |
echo output(class12::STR . '大方'); | |
$obj = new class12(); | |
// 直接echo 即可呼叫__toString()方法,或是轉型成string也可呼叫 | |
echo output($obj); | |
$obj->setName('QQ'); | |
echo output($obj); | |
// 以下為簡單應用,不過實際上必需還要建立抽象類,然後再繼承去建立每個元素的個別功能,不過我懶了Orz | |
class element | |
{ | |
protected $elements = array(); | |
protected $propertys = array(); | |
protected $tag; | |
public function __construct($tag) | |
{ | |
$this->tag = $tag; | |
} | |
public function __toString() | |
{ | |
$str = ''; | |
$attbs = ''; | |
foreach($this->elements as $key => $value) | |
{ | |
$str .= $value. '<br/>'; | |
} | |
foreach($this->propertys as $key => $value) | |
{ | |
$attbs .= ' ' . $key . '="' . $value . '"'; | |
} | |
return '<' . $this->tag . $attbs . '>' . $str . '</' . $this->tag . '>'; | |
} | |
public function setProperty($key, $value) | |
{ | |
$this->propertys[$key] = $value; | |
// return $this 白話意義就是回傳自己,也就是回傳一個物件,而那個物件是自己,所以可以使用像class4那樣連續呼叫一樣 | |
return $this; | |
} | |
public function appendElements($tag) | |
{ | |
$element = new element($tag); | |
$this->elements[] = $element; | |
// 需注意的是,一開始有提到直接用等號的話是複製參考,所以這邊$element和$this->elements[]指向的都是同一個物件 | |
return $element; | |
} | |
} | |
$obj = new element('form'); | |
$obj->setProperty('method', 'post')->setProperty('action', 'class.php'); | |
$obj->appendElements('input')->setProperty('value', '輸入A'); | |
$obj->appendElements('input')->setProperty('value', '輸入B'); | |
$obj->appendElements('input')->setProperty('type', 'checkbox'); | |
$obj->appendElements('input')->setProperty('type', 'checkbox')->setProperty('checked', 'checked'); | |
$obj->appendElements('input')->setProperty('type', 'radio')->setProperty('name', 'A'); | |
$obj->appendElements('input')->setProperty('type', 'radio')->setProperty('name', 'A')->setProperty('checked', 'checked'); | |
$obj->appendElements('input')->setProperty('type', 'radio')->setProperty('name', 'B')->setProperty('checked', 'checked'); | |
$obj->appendElements('input')->setProperty('type', 'radio')->setProperty('name', 'B'); | |
$obj->appendElements('textarea'); | |
$obj->appendElements('input')->setProperty('type', 'reset')->setProperty('value', '重新設定'); | |
$obj->appendElements('input')->setProperty('type', 'submit')->setProperty('value', '送出資料'); | |
echo $obj; | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment