[php tech.] PHP 5 工作筆記

雖然寫這種東西點閱率應該很低,不過,可以充很大的版面(沒有誤),也算是功德一件。

這次要筆記的東西,是 PHP 5 的一些新東西,還有順便是從 TextCube Night build 中找到的一些新玩意。俗話說得好,拷貝是學習的不二法門 (肯定的),但是單純的拷貝並不會進步,我作筆記總可以吧 (哈哈哈)。

首先是 Abstract Class (抽象類別) 與 Interface (介面) 的介紹,在 php.net 裡面對於 Interface 的介紹少之又少,所以跑去問問估狗大神,還不少資料,繁簡體都有。

我這邊整理一下。

Interface 只是定義一個介面,這個介面裡面可以放 private, public, protected 三種類型的函式、變數。當然,除了 public 之外,除非必要,我想大概不會想放其它兩種。都要用來 implements 了,不 public 的話要怎麼 implements 呢 (笑)。

implements (實作) 跟 extends (繼承或衍生,因程序而異) 這兩者應該不難見,只是 extends 好像比較常見就是。

以下整理自出處:http://ronnywang.pixnet.net/blog/post/19130725

我在這邊另外附上實作範例,幫助了解。

interface Iterator {
    public function rewind();
   public function current();
   public function key();
   public function next();
   public function valid();
}

interface IteratorAggregate {
    public function getIterator();
}

Iterator 跟 IteratorAggregate 兩者,是一種迴圈介面,可以被 foreach 或是 for 迴圈使用。後者是指定迴圈最大值 (總值),並傳回給前者,當然,這樣的回傳動作需要 implements Class 去做,以下給各位一個實作範例比較清楚。另外,這兩種 (甚至接下來回提到的 Interface 都是 PHP 5 已經內建的,不需要再定義了)。

<?php
class CI implements Iterator {
    private $obj;
    private $num;

    public function __construct($obj) {
        $this->obj = $obj;
    }
    public function rewind() {
        $this->num = 0;
    }
    public function valid() {
        return $this->num < $this->obj->max;
    }
    public function key() {
        return $this->num;
    }
    public function current() {
        switch($this->num) {
           case 0: return "1st";
           case 1: return "2nd";
           case 2: return "3rd";
           default: return $this->num."th";
        }
    }
    public function next() {
        $this->num++;
    }
}

class CIA implements IteratorAggregate {
   public $max = 1;
   public function getIterator() {
       return new CI($this);
   }
}
// class CI 與 CIA 是自己取的名稱(這是廢話吧)
$obj = new CIA;
// 指定這個 IteratorAggregate 的最大值(在 Class CIA 裏面我預設給 1 而已)
$obj->max = 10;

// 使用 foreach 
echo '使用 foreach...<br /> ';
foreach($obj as $key => $val) {
   echo $key,' = ',$val,'<br />';
}

// 相當於使用 for 迴圈的用法
echo '相當於使用 for 迴圈的用法...<br /> ';
$it = $obj->getIterator();
for($it->rewind(); $it->valid(); $it->next()) {
   $val = $it->current();
   $key = $it->key();
   echo $key,' = ',$val,'<br />';
}
unset($it);

/* 顯示結果

使用 foreach...
0 = 1st
1 = 2nd
2 = 3rd
3 = 3th
4 = 4th
5 = 5th
6 = 6th
7 = 7th
8 = 8th
9 = 9th
相當於使用 for 迴圈的用法...
0 = 1st
1 = 2nd
2 = 3rd
3 = 3th
4 = 4th
5 = 5th
6 = 6th
7 = 7th
8 = 8th
9 = 9th
*/

Countable 可以將 implements class 做 count 使用。

interface Countable {
   public function count();
}
<?php
class CI implements Countable {
    private $intCount = null;
    public function __construct($intCount){
        $this->intCount = $intCount;
    }
    public function count(){
        return $this->intCount;
    }
}

$obj = new CI(15);
echo count($obj).'<br />';
echo $obj->count().'<br />';

/* 顯示結果
15
15
*/

有人大概會問說,為什麼不用 $obj[$pos] 去取結果值,這樣是不行的,因為陣列的方式必須使用另一個 interface ArrayAccess 的方式去做。

interface SeekableIterator {
   public function rewind();
   public function current();
   public function key();
   public function next();
   public function valid();
   public function seek($pos);
}
<?php
class CI implements SeekableIterator {
    private $obj;
    private $num;

    public function __construct($obj) {
        $this->obj = $obj;
    }
    public function rewind() {
        $this->num = 0;
    }
    public function valid() {
        return $this->num < $this->obj->max;
    }
    public function key() {
        return $this->num;
    }
    public function current() {
        switch($this->num) {
           case 0: return "1st";
           case 1: return "2nd";
           case 2: return "3rd";
           default: return $this->num."th";
        }
    }
    public function next() {
        $this->num++;
    }
    public function seek($pos) {
        $__tmp = $this->num;
        $this->num = $pos;
        $pos = $this->current();
        $this->num = $__tmp;
        return $pos;
    }
}

class CIA implements IteratorAggregate {
    public $max = 1;
    function getIterator() {
        return new CI($this);
    }
}

$obj = new CIA;
// 指定這個 IteratorAggregate 的最大值(在 Class CIA 裏面我預設給 1 而已)
$obj->max = 10;

// 這裡僅介紹 seek 的用法,其它迴圈用法與 Iterator, IteratorAggregate 相同
$it = $obj->getIterator();
echo $it->seek(5);

/* 顯示結果
5th
*/

底下來介紹 ArrayAccess,這是 ArrayAccess 在 PHP 裡面的定義。

interface ArrayAccess {
   offsetExists ($offset) // boolean
   offsetGet ($offset)  // mixed
   offsetSet ($offset, $value)  // void
   offsetUnset ($offset)  // void
}

簡單的範例如下。

class CI implements ArrayAccess {
    private $configarray; 

    public function __construct() {
        $this->configarray = array("John"=>"Male", "May"=>"Female"); 
    }
    public function offsetExists($index) {
        return isset($this->configarray[$index]); 
    }
    public function offsetGet($index) { 
        return $this->configarray[$index]; 
    }
    public function offsetSet($index, $newvalue) { 
        $this->configarray[$index] = $newvalue; 
    }
    public function offsetUnset($index) { 
        unset($this->configarray[$index]); 
    } 
}

$obj = new CI();
echo '原有陣列為:array("John"=>"Male", "May"=>"Female")<br />';
echo 'offsetGet("May") => '.($obj->offsetGet("May")).'<br />';
echo 'offsetExists("May") => ';
echo ($obj->offsetExists("May")) ? 'yes' : 'no';
echo '<br />';
$obj->offsetSet("May", "John's wife.");
// 使用 offsetSet 修改原有陣列內的值
echo '使用 offsetSet 修改原有陣列內的值<br />';
echo 'offsetGet("May") => '.($obj->offsetGet("May")).'<br />';
// 使用 offsetSet 新增原有陣列內的值
echo '使用 offsetSet 新增原有陣列內的值<br />';
$obj->offsetSet("Jasmin", "John's sister.");
echo 'offsetGet("Jasmin") => '.($obj->offsetGet("Jasmin")).'<br />';
echo '目前陣列內容為:array("John"=>"Male", "May"=>"John\'s wife.", "Jasmin", "John\'s sister.")<br />';
// 使用 offsetUnset 刪除原有陣列內的值
$obj->offsetUnset("May");
echo 'offsetExists("May") => ';
echo ($obj->offsetExists("May")) ? 'yes' : 'no';
echo '<br />';
echo '目前陣列內容為:array("John"=>"Male", "Jasmin", "John\'s sister.")<br />';

/* 顯示結果
原有陣列為:array("John"=>"Male", "May"=>"Female")
offsetGet("May") => Female
offsetExists("May") => yes
使用 offsetSet 修改原有陣列內的值
offsetGet("May") => John's wife.
使用 offsetSet 新增原有陣列內的值
offsetGet("Jasmin") => John's sister.
目前陣列內容為:array("John"=>"Male", "May"=>"John's wife.", "Jasmin", "John's sister.")
offsetExists("May") => no
目前陣列內容為:array("John"=>"Male", "Jasmin", "John's sister.")
*/

這個就應該比較容易理解,其實跟 serialize 差不多。這裡有一篇文章有非常詳盡的說明,值得一看:PHP 序列化(serialize)格式详解

interface Serializable {
   public function serialize();
   public function unserialize($serialized)
}

至於範例,我不想舉了,因為這牽扯到一些傳值傳址的問題,強烈建議閱讀我上面所提供的那篇文章。

誒... Abstract Class 呢?

我好懶啊... 請自行翻閱:

先告一段落,以後想到什麼在補上吧。

附帶一提,TextCube 從 1.8 以後的程式結構又改了,不知道對往後修改有無影響?目前縱觀而言,似乎是沒有 (遠目)。

Hina Chen
偏執與強迫症的患者,算不上是無可救藥,只是我已經遇上我的良醫了。
Taipei