<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>網站製作學習誌- PHP</title>
<link>http://blog.roodo.com/jaceju/archives/cat_13112.html</link>
<description>
這裡不更新了喔~歡迎到我的新家 :D
</description>
<language>zh-tw</language>
<generator>Roodo Blog System</generator>
<copyright>All Rights Reserved</copyright>
<atom:link href="http://blog.roodo.com/jaceju/archives/cat_13112.xml" rel="self" type="application/rss+xml" />
<item>
	<title>[PHP] Smarty 樣版小技巧整理</title>
	<description><![CDATA[
			在 Smarty 中，我們可以用以下的語法來完成類似 for 迴圈的效果： 
{section name=&quot;forLoop&quot; start=1 loop=10}
{/section}
其中 start 即為起始值， loop 為小於而不等於的終值。
如果以 PHP 語法來表示，則如下所示：
for ($i = 1; $i &lt; 10; $i ++) {
    // ...
} 
使用無參數原生 PHP 函式
我們可以在樣版中使用許多原生的 PHP 函式 (但還是有例外) 來當做變數修飾函式，不過如果有些函式不需要參數時，我們可以用以下語法來呼叫：
{''|@time}
當然這裡的空字串對 time 函式來說是沒有意義的，而在函式前加上 @ 號，表示要直接呼叫原生 PHP 函式。
在 assign 設定 default 值
假設當樣版變數不存在或可轉換為 false 值時，我們會希望顯示一個預設值；而 Smarty 剛好就提供了一個 default 變數修飾函式讓我們使用，語法如下： 
{$test|default:'NULL'}
而 default 變數修飾函式不僅只有在呈現變數能用，也能在樣版 assign 變數時使用，如下：
{assign var=value2 value=$value1|default:0}
註：當然不只有 default ，幾乎所有變數修飾函式都能在 assign 或其他可接受變數的樣版函式裡使用。 
物件導向語法
Smarty 也支援 PHP 的物件導向語法，例如呼叫某物件函式：
{$test-&gt;getFakeValue()}
我們也能在樣版函式中，使用物件導向語法，而且後面也能串接變數修飾函式：
{assign var=nullValue value=$test-&gt;getNullValue()|default:'NULL'}
利用 config 變數或常數來當做變數修飾函式的參數
通常我們會用到設定值來避免重複設定一些常數值，例如用 PHP 陣列的方式指定給 Smarty ： 
$config = array(
    'date' =&gt; '%Y/%m/%d',
    'time' =&gt; '%H:%M',
);
$smarty-&gt;assign($config);
在樣版裡就可以這樣用：
{$date|date_format:$config.date}
我們也可以利用 PHP 的常數來當做設定，在樣版可以用「 $smarty.const.常數名稱」來取得常數內容：
{$date|date_format:$smarty.const.DATE_FORMAT}
當然，我們也可以透過 Smarty 內建的 config 機制；例如我們有個 config.conf ，內容如下：
date = &quot;%Y/%m/%d&quot;
time = &quot;%H:%M&quot; 
然後在樣版內改用：
{config_load file=&quot;config.conf&quot;}
{$date|date_format:#date#} {$time|date_format:#time#}
其中 &nbsp;#date# 與 #time# 就是從 config.conf 中讀取的。 
註：感謝 Smarty 頭號粉絲 - 小魚提供以上技巧。
用 {cycle} 配合 CSS 來做表格列交替變色
我們可以用 cycle 配合 sction 或 foreach ，來做出交替變色的表格，語法如下： 
{secion ....}
.....
&lt;tr class=&quot;{cycle values=&quot;normal,alt&quot;}&quot;&gt;
.....
{/secion}
可以看出，它比使用 {if} 來得簡潔許多：
&lt;tr class=&quot;{if $smarty.section.forLoop.iteration is odd}normal{else}alt{/if}&quot;&gt;
註：感謝 Smarty 頭號粉絲 - 小魚提供以上技巧。
如果還有相關技巧的話，將會陸續再更新。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>在 Smarty 中，我們可以用以下的語法來完成類似 for 迴圈的效果： </p>
<pre><code>{section name=&quot;forLoop&quot; start=1 loop=10}
{/section}</code></pre>
<p>其中 start 即為起始值， loop 為小於而不等於的終值。</p>
<p>如果以 PHP 語法來表示，則如下所示：</p>
<pre><code>for ($i = 1; $i &lt; 10; $i ++) {
    // ...
} </code></pre>
<h2>使用無參數原生 PHP 函式</h2>
<p>我們可以在樣版中使用許多原生的 PHP 函式 (但還是有例外) 來當做變數修飾函式，不過如果有些函式不需要參數時，我們可以用以下語法來呼叫：</p>
<pre><code>{''|@time}</code></pre>
<p>當然這裡的空字串對 time 函式來說是沒有意義的，而在函式前加上 @ 號，表示要直接呼叫原生 PHP 函式。</p>
<h2>在 assign 設定 default 值</h2>
<p>假設當樣版變數不存在或可轉換為 false 值時，我們會希望顯示一個預設值；而 Smarty 剛好就提供了一個 default 變數修飾函式讓我們使用，語法如下： </p>
<pre><code>{$test|default:'NULL'}</code></pre>
<p>而 default 變數修飾函式不僅只有在呈現變數能用，也能在樣版 assign 變數時使用，如下：</p>
<pre><code>{assign var=value2 value=$value1|default:0}</code></pre>
<p class="note">註：當然不只有 default ，幾乎所有變數修飾函式都能在 assign 或其他可接受變數的樣版函式裡使用。 </p>
<h2>物件導向語法</h2>
<p>Smarty 也支援 PHP 的物件導向語法，例如呼叫某物件函式：</p>
<pre><code>{$test-&gt;getFakeValue()}</code></pre>
<p>我們也能在樣版函式中，使用物件導向語法，而且後面也能串接變數修飾函式：</p>
<pre><code>{assign var=nullValue value=$test-&gt;getNullValue()|default:'NULL'}</code></pre>
<h2>利用 config 變數或常數來當做變數修飾函式的參數</h2>
<p>通常我們會用到設定值來避免重複設定一些常數值，例如用 PHP 陣列的方式指定給 Smarty ： </p>
<pre><code>$config = array(
    'date' =&gt; '%Y/%m/%d',
    'time' =&gt; '%H:%M',
);
$smarty-&gt;assign($config);</code></pre>
<p>在樣版裡就可以這樣用：</p>
<pre><code>{$date|date_format:$config.date}</code></pre>
<p>我們也可以利用 PHP 的常數來當做設定，在樣版可以用「 $smarty.const.常數名稱」來取得常數內容：</p>
<pre><code>{$date|date_format:$smarty.const.DATE_FORMAT}</code></pre>
<p>當然，我們也可以透過 Smarty 內建的 config 機制；例如我們有個 config.conf ，內容如下：</p>
<pre><code>date = &quot;%Y/%m/%d&quot;
time = &quot;%H:%M&quot; </code></pre>
<p>然後在樣版內改用：</p>
<pre><code>{config_load file=&quot;config.conf&quot;}
{$date|date_format:#date#} {$time|date_format:#time#}</code></pre>
<p>其中 &nbsp;#date# 與 #time# 就是從 config.conf 中讀取的。 </p>
<p class="note">註：感謝 <a href="http://www.fishbear.idv.tw/babyblog2008/main.php?B_ID=48" target="_blank">Smarty 頭號粉絲 - 小魚</a>提供以上技巧。</p>
<h2>用 {cycle} 配合 CSS 來做表格列交替變色</h2>
<p>我們可以用 cycle 配合 sction 或 foreach ，來做出交替變色的表格，語法如下： </p>
<pre><code>{secion ....}
.....
&lt;tr class=&quot;{cycle values=&quot;normal,alt&quot;}&quot;&gt;
.....
{/secion}</code></pre>
<p>可以看出，它比使用 {if} 來得簡潔許多：</p>
<pre><code>&lt;tr class=&quot;{if $smarty.section.forLoop.iteration is odd}normal{else}alt{/if}&quot;&gt;</code></pre>
<p class="note">註：感謝 <a href="http://www.fishbear.idv.tw/babyblog2008/main.php?B_ID=48" target="_blank">Smarty 頭號粉絲 - 小魚</a>提供以上技巧。</p>
<p>如果還有相關技巧的話，將會陸續再更新。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/7387781.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/7387781.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 16 Oct 2008 22:27:29 +0800</pubDate>
</item>
<item>
	<title>[PHP] Session 相關文章</title>
	<description><![CDATA[
			身為 PHP 開發者，我其實對 PHP Session 的處理機制還是一知半解。
這次因為有個大案子上線的關係，讓我真的遇到了 Session 過多的問題。
這裡強力推薦宗董寫的一篇好文： PHP session 暫存檔過多的注意事項。
不過基本上在連線數會很高的網站，還是建議使用 MySQL 或 memcache 來當做 Session 的儲存媒體。
如果要使用 MySQL 的話，我們可以利用 session_set_save_handler 來建立資料庫連線並存取 Session 資料。
而使用 memcache 的話，可以參考 PHP 官方提供的方法，程式如下： 
&lt;?php
$host = 'localhost';
$port = '11211';
$session_save_path = &quot;tcp://$host:$port?persistent=1&amp;weight=2&amp;timeout=2&amp;retry_interval=10,  ,tcp://$host:$port  &quot;;
ini_set('session.save_handler', 'memcache');
ini_set('session.save_path', $session_save_path);
希望以上的資訊能提供大家對 PHP 處理 Session 有更進一步的瞭解。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>身為 PHP 開發者，我其實對 PHP Session 的處理機制還是一知半解。</p>
<p>這次因為有個大案子上線的關係，讓我真的遇到了 Session 過多的問題。</p>
<p>這裡強力推薦<a href="http://plog.longwin.com.tw">宗董</a>寫的一篇好文： <a href="http://plog.longwin.com.tw/my_note-unix/2008/10/16/php-too-more-session-file-set-2008">PHP session 暫存檔過多的注意事項</a>。</p>
<p>不過基本上在連線數會很高的網站，還是建議使用 MySQL 或 memcache 來當做 Session 的儲存媒體。</p>
<p>如果要使用 MySQL 的話，我們可以利用 <a href="http://www.php.net/manual/en/function.session-set-save-handler.php">session_set_save_handler</a> 來建立資料庫連線並存取 Session 資料。</p>
<p>而使用 memcache 的話，可以參考 PHP 官方提供的<a href="http://www.php.net/manual/en/memcache.examples.php">方法</a>，程式如下： </p>
<pre><code>&lt;?php
$host = 'localhost';
$port = '11211';
$session_save_path = &quot;tcp://$host:$port?persistent=1&amp;weight=2&amp;timeout=2&amp;retry_interval=10,  ,tcp://$host:$port  &quot;;
ini_set('session.save_handler', 'memcache');
ini_set('session.save_path', $session_save_path);</code></pre>
<p>希望以上的資訊能提供大家對 PHP 處理 Session 有更進一步的瞭解。 </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/7385665.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/7385665.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 16 Oct 2008 12:34:46 +0800</pubDate>
</item>
<item>
	<title>[PHP] 觀念教室 - 取值函式</title>
	<description><![CDATA[
			通常在物件導向的開發過程裡，我們常會將類別的屬性隱藏起來，然後透過設值及取值函式來存取它們，也就是我們常說的 setter/getter 。
例如：
&lt;?php
class SampleClass
{
    private $_attr = 0;

    public function setAttr($value)
    {
        $this-&gt;_attr = (int) $value;
    }
    
    public function getAttr()
    {
        return $this-&gt;_attr;
    }
}
不過設值函式並不是本文的重點，這裡我先略過不談。
從上面的程式碼裡可以看到，取值函式似乎是一段再簡單不過的程式碼，它只是很單純的把物件內部的屬性值回傳而已。
但如果今天我們的屬性值是需要經過計算才能夠回傳的話，怎麼辦呢？我們應該把計算的邏輯寫在取值函式裡嗎？
在討論之前，我們先來假設一個簡單的狀況：
「現在有一個購物車程式，在使用者購買金額未超過 500 元時，我們要在總金額上加上運費 100 元；然而當總金額滿 500 元時，就不需要加入運費了。」
以下就是這個簡化過的購物車程式碼：
&lt;?php
/**
 * 購物車類別
 *
 */
class Cart
{
    /**
     * 購物車項目列表
     *
     * @var array
     */
    private $_itemList = array();

    /**
     * 總金額
     *
     * @var int
     */
    private $_total = 0;

    /**
     * 加入購物車項目
     *
     * @param array $item
     * @return Cart
     */
    public function addItem($item)
    {
        $this-&gt;_itemList[] = $item;
        return $this;
    }

    /**
     * 更新購物車
     *
     * @return Cart
     */
    public function refresh()
    {
        $this-&gt;_total = 0;
        foreach ($this-&gt;_itemList as $item) {
            $this-&gt;_total += $item['subTotal'];
        }
        return $this;
    }

    /**
     * 清空購物車
     *
     * @return void
     */
    public function clearAll()
    {
        $this-&gt;_itemList = array();
        $this-&gt;_total = 0;
    }

    /**
     * 取得總金額
     *
     * @return int
     */
    public function getTotal()
    {
        if ($this-&gt;_total &lt; 500) {
            $this-&gt;_total += 100;
        }
        return $this-&gt;_total;
    }
}
註：我故意省略掉數量、單價等資訊。
在邏輯上，這段程式碼似乎沒有什麼問題，在取得總金額時判斷是否應該加上運費看起來是很合理的。
是嗎？
相信有經驗的朋友，思考一下就能看出這個程式的邏輯錯誤。
看不出來的朋友也沒關係，我簡單寫個測試程式來說明：
&lt;?php

require 'Cart.php';

// 建立購物車物件
$cart = new Cart();

// 顯示總金額 (金額為 520 元，大於 500 元，故不加上運費)
echo $cart
    -&gt;addItem(array('name' =&gt; '商品1', 'subTotal' =&gt; 120))
    -&gt;addItem(array('name' =&gt; '商品2', 'subTotal' =&gt; 100))
    -&gt;addItem(array('name' =&gt; '商品3', 'subTotal' =&gt; 50))
    -&gt;addItem(array('name' =&gt; '商品4', 'subTotal' =&gt; 70))
    -&gt;addItem(array('name' =&gt; '商品5', 'subTotal' =&gt; 80))
    -&gt;refresh()
    -&gt;getTotal(), &quot;\n&quot;;

// 再顯示一次總金額 (正確顯示 520 元)
echo $cart-&gt;getTotal(), &quot;\n&quot;;

// 先清空購物車
$cart-&gt;clearAll();

// 顯示總金額 (金額為 340 元，小於 500 元，故加上 100 元運費)
echo $cart
    -&gt;addItem(array('name' =&gt; '商品1', 'subTotal' =&gt; 120))
    -&gt;addItem(array('name' =&gt; '商品2', 'subTotal' =&gt; 100))
    -&gt;addItem(array('name' =&gt; '商品3', 'subTotal' =&gt; 50))
    -&gt;addItem(array('name' =&gt; '商品4', 'subTotal' =&gt; 70))
    -&gt;refresh()
    -&gt;getTotal(), &quot;\n&quot;;

// 再顯示一次總金額 (錯了！竟然變成 540 元！)
echo $cart-&gt;getTotal(), &quot;\n&quot;;
從上面的程式可以發現，當我們購買金額小於 500 元時， Cart::getTotal 這個取值函式會幫我們自動加上運費。但是我們第二次呼叫 Cart::getTotal 時，程式竟然又幫我們加上了一次運費！
原因我想大家都看出來了，也就是說我們根本不應該在 Cart::getTotal 中加入運費判斷這件事情。這裡正確的做法是應該把運費判斷的條件寫在 Cart::refresh 這個方法裡，而 Cart::getTotal 應該要很單純地只是回傳 $_total 這個屬性值，也就是：
   /**
     * 更新購物車
     *
     * @return Cart
     */
    public function refresh()
    {
        $this-&gt;_total = 0;
        foreach ($this-&gt;_itemList as $item) {
            $this-&gt;_total += $item['subTotal'];
        }

        // 將運費判斷改到這裡
        if ($this-&gt;_total &lt; 500) {
            $this-&gt;_total += 100;
        }
        return $this;
    }
或許有人會問，什麼狀況下你會去呼叫兩次 Cart::getTotal ？其實答案很多，例如有時候在 MVC 模式下，我們常會用 Model 的取值函式來呈現其對應的值，這時我們就可能會多次去呼叫 Cart::getTotal ；也有可能其他團隊成員並不知道 Cart::getTotal 的運作方式，他們一直很快樂地使用著 Cart::getTotal 來取得總金額，直到慘劇的發生...
所以這裡我們暫時得到一個結論：取值函式不應該參與運算邏輯。
是嗎？
其實這樣的結論還是有問題的，接下來我們來看看以下這個計時器類別：
&lt;?php

class Timer
{
    public function getTime()
    {
        return time();
    }
}

$timer = new Timer();

echo $timer-&gt;getTime(), &quot;\n&quot;;
sleep(2);
echo $timer-&gt;getTime(), &quot;\n&quot;;
很明顯的，對計時器這種物件來說，即時性是很重要的，也就是說每一次取得的時間是會變動的。在這裡，取值函式就參與了時間的計算。
因此，我們要修正剛剛的結論，為它加入一個但書：除非有即時性的需求，否則取值函式不應該參與運算邏輯。
有其他想法嗎？歡迎大家一起討論。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>通常在物件導向的開發過程裡，我們常會將類別的屬性隱藏起來，然後透過設值及取值函式來存取它們，也就是我們常說的 setter/getter 。</p>
<p>例如：</p>
<pre><code>&lt;?php
class SampleClass
{
    private $_attr = 0;

    public function setAttr($value)
    {
        $this-&gt;_attr = (int) $value;
    }
    
    public function getAttr()
    {
        return $this-&gt;_attr;
    }
}</code></pre>
<p>不過設值函式並不是本文的重點，這裡我先略過不談。</p>
<p>從上面的程式碼裡可以看到，取值函式似乎是一段再簡單不過的程式碼，它只是很單純的把物件內部的屬性值回傳而已。</p>
<p>但如果今天我們的屬性值是需要經過計算才能夠回傳的話，怎麼辦呢？我們應該把計算的邏輯寫在取值函式裡嗎？</p>
<p>在討論之前，我們先來假設一個簡單的狀況：</p>
<p>「現在有一個購物車程式，在使用者購買金額未超過 500 元時，我們要在總金額上加上運費 100 元；然而當總金額滿 500 元時，就不需要加入運費了。」</p>
<p>以下就是這個簡化過的購物車程式碼：</p>
<pre><code>&lt;?php
/**
 * 購物車類別
 *
 */
class Cart
{
    /**
     * 購物車項目列表
     *
     * @var array
     */
    private $_itemList = array();

    /**
     * 總金額
     *
     * @var int
     */
    private $_total = 0;

    /**
     * 加入購物車項目
     *
     * @param array $item
     * @return Cart
     */
    public function addItem($item)
    {
        $this-&gt;_itemList[] = $item;
        return $this;
    }

    /**
     * 更新購物車
     *
     * @return Cart
     */
    public function refresh()
    {
        $this-&gt;_total = 0;
        foreach ($this-&gt;_itemList as $item) {
            $this-&gt;_total += $item['subTotal'];
        }
        return $this;
    }

    /**
     * 清空購物車
     *
     * @return void
     */
    public function clearAll()
    {
        $this-&gt;_itemList = array();
        $this-&gt;_total = 0;
    }

    /**
     * 取得總金額
     *
     * @return int
     */
    public function getTotal()
    {
        if ($this-&gt;_total &lt; 500) {
            $this-&gt;_total += 100;
        }
        return $this-&gt;_total;
    }
}</code></pre>
<p class="note">註：我故意省略掉數量、單價等資訊。</p>
<p>在邏輯上，這段程式碼似乎沒有什麼問題，在取得總金額時判斷是否應該加上運費看起來是很合理的。</p>
<p><strong>是嗎？</strong></p>
<p>相信有經驗的朋友，思考一下就能看出這個程式的邏輯錯誤。</p>
<p>看不出來的朋友也沒關係，我簡單寫個測試程式來說明：</p>
<pre><code>&lt;?php

require 'Cart.php';

// 建立購物車物件
$cart = new Cart();

// 顯示總金額 (金額為 520 元，大於 500 元，故不加上運費)
echo $cart
    -&gt;addItem(array('name' =&gt; '商品1', 'subTotal' =&gt; 120))
    -&gt;addItem(array('name' =&gt; '商品2', 'subTotal' =&gt; 100))
    -&gt;addItem(array('name' =&gt; '商品3', 'subTotal' =&gt; 50))
    -&gt;addItem(array('name' =&gt; '商品4', 'subTotal' =&gt; 70))
    -&gt;addItem(array('name' =&gt; '商品5', 'subTotal' =&gt; 80))
    -&gt;refresh()
    -&gt;getTotal(), &quot;\n&quot;;

// 再顯示一次總金額 (正確顯示 520 元)
echo $cart-&gt;getTotal(), &quot;\n&quot;;

// 先清空購物車
$cart-&gt;clearAll();

// 顯示總金額 (金額為 340 元，小於 500 元，故加上 100 元運費)
echo $cart
    -&gt;addItem(array('name' =&gt; '商品1', 'subTotal' =&gt; 120))
    -&gt;addItem(array('name' =&gt; '商品2', 'subTotal' =&gt; 100))
    -&gt;addItem(array('name' =&gt; '商品3', 'subTotal' =&gt; 50))
    -&gt;addItem(array('name' =&gt; '商品4', 'subTotal' =&gt; 70))
    -&gt;refresh()
    -&gt;getTotal(), &quot;\n&quot;;

// 再顯示一次總金額 (錯了！竟然變成 540 元！)
echo $cart-&gt;getTotal(), &quot;\n&quot;;</code></pre>
<p>從上面的程式可以發現，當我們購買金額小於 500 元時， Cart::getTotal 這個取值函式會幫我們自動加上運費。但是我們第二次呼叫 Cart::getTotal 時，程式竟然又幫我們加上了一次運費！</p>
<p>原因我想大家都看出來了，也就是說我們根本不應該在 Cart::getTotal 中加入運費判斷這件事情。這裡正確的做法是應該把運費判斷的條件寫在 Cart::refresh 這個方法裡，而 Cart::getTotal 應該要很單純地只是回傳 $_total 這個屬性值，也就是：</p>
<pre><code>   /**
     * 更新購物車
     *
     * @return Cart
     */
    public function refresh()
    {
        $this-&gt;_total = 0;
        foreach ($this-&gt;_itemList as $item) {
            $this-&gt;_total += $item['subTotal'];
        }

        <strong>// 將運費判斷改到這裡</strong>
        if ($this-&gt;_total &lt; 500) {
            $this-&gt;_total += 100;
        }
        return $this;
    }</code></pre>
<p>或許有人會問，什麼狀況下你會去呼叫兩次 Cart::getTotal ？其實答案很多，例如有時候在 MVC 模式下，我們常會用 Model 的取值函式來呈現其對應的值，這時我們就可能會多次去呼叫 Cart::getTotal ；也有可能其他團隊成員並不知道 Cart::getTotal 的運作方式，他們一直很快樂地使用著 Cart::getTotal 來取得總金額，直到慘劇的發生...</p>
<p>所以這裡我們暫時得到一個結論：<strong>取值函式不應該參與運算邏輯。</strong></p>
<p><strong>是嗎？</strong></p>
<p>其實這樣的結論還是有問題的，接下來我們來看看以下這個計時器類別：</p>
<pre><code>&lt;?php

class Timer
{
    public function getTime()
    {
        return time();
    }
}

$timer = new Timer();

echo $timer-&gt;getTime(), &quot;\n&quot;;
sleep(2);
echo $timer-&gt;getTime(), &quot;\n&quot;;</code></pre>
<p>很明顯的，對計時器這種物件來說，即時性是很重要的，也就是說每一次取得的時間是會變動的。在這裡，取值函式就參與了時間的計算。</p>
<p>因此，我們要修正剛剛的結論，為它加入一個但書：<strong>除非有即時性的需求，否則取值函式不應該參與運算邏輯。</strong></p>
<p>有其他想法嗎？歡迎大家一起討論。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/7078107.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/7078107.html</guid>
	<category> PHP</category>
	<pubDate>Sun, 31 Aug 2008 12:01:30 +0800</pubDate>
</item>
<item>
	<title>[PHP] PHP 5.3 的 Lambda 和 closure ？</title>
	<description><![CDATA[
			這篇也 Lag....這是前陣子的消息。
PHP 5.3 將有可能會有 Lambda (黏巴達？) 和 closure ，來源為 Request for Comments: Lambda functions and closures 這篇文章，所以以後 call_user_func 就不必再用蹩腳的字串來做為函式內容了。而且這是不是也表示 PHP 不但向 Java 靠攏，也開始向 JavaScript 靠攏了？
註：所以 Mark 剛剛跟我說 PHP 快變四不像了。
Lambda 語法如下：
function &amp; (parameters) use (lexical vars) { body }
範例：
$lambda = function () { echo &quot;Hello World!\n&quot;; };
可以這樣用：
$lambda ();
call_user_func($lambda);
call_user_func_array($lambda, array());
所以 call_user_func 系列函式就可以用 Lambda 了。 
進階的 Lambda 範例：
function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', '&amp;nbsp;').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}
Closure 語法：
function (normal parameters) use ($var1, $var2, &amp;$refvar) {}
範例：
function replace_in_array ($search, $replacement, $array) {
    $map = function ($text) use ($search, $replacement) {
        if (strpos ($text, $search) &gt; 50) {
            return str_replace($search, $replacement, $text);
        } else {
            return $text;
        }
    };
    return array_map($map, $array);
}
可以看到原來可以用 callback 的函式，應該都能接受 closure 。 
其他就請參考來源文章囉。
相關文章 

php 5.3: notes about closures and lambda functions 
php 5.3将提供改进的Lambda函数 


		]]>
	</description>
	<content:encoded><![CDATA[
			<p>這篇也 Lag....這是前陣子的消息。</p>
<p>PHP 5.3 將有可能會有 Lambda (黏巴達？) 和 closure ，來源為 <a href="http://wiki.php.net/rfc/closures">Request for Comments: Lambda functions and closures</a> 這篇文章，所以以後 call_user_func 就不必再用蹩腳的字串來做為函式內容了。而且這是不是也表示 PHP 不但向 Java 靠攏，也開始向 JavaScript 靠攏了？</p>
<p class="note">註：所以 <a href="http://blog.markplace.net/" target="_blank">Mark</a> 剛剛跟我說 PHP 快變四不像了。</p>
<p>Lambda 語法如下：</p>
<pre><code>function &amp; (parameters) use (lexical vars) { body }</code></pre>
<p>範例：</p>
<pre><code>$lambda = function () { echo &quot;Hello World!\n&quot;; };</code></pre>
<p>可以這樣用：</p>
<pre><code>$lambda ();
call_user_func($lambda);
call_user_func_array($lambda, array());</code></pre>
<p>所以 call_user_func 系列函式就可以用 Lambda 了。 </p>
<p>進階的 Lambda 範例：</p>
<pre><code>function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', '&amp;nbsp;').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}</code></pre>
<p>Closure 語法：</p>
<pre><code>function (normal parameters) use ($var1, $var2, &amp;$refvar) {}</code></pre>
<p>範例：</p>
<pre><code>function replace_in_array ($search, $replacement, $array) {
    $map = function ($text) use ($search, $replacement) {
        if (strpos ($text, $search) &gt; 50) {
            return str_replace($search, $replacement, $text);
        } else {
            return $text;
        }
    };
    return array_map($map, $array);
}</code></pre>
<p>可以看到原來可以用 callback 的函式，應該都能接受 closure 。 </p>
<p>其他就請參考來源文章囉。</p>
<h2>相關文章 </h2>
<ul>
<li><a href="http://dev.iordanov.net/archives/9">php 5.3: notes about closures and lambda functions</a> </li>
<li><a href="http://www.ooso.net/index.php/archives/463">php 5.3将提供改进的Lambda函数</a> </li>
</ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/6541789.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/6541789.html</guid>
	<category> PHP</category>
	<pubDate>Tue, 22 Jul 2008 17:41:48 +0800</pubDate>
</item>
<item>
	<title>[PHP] PHP 5.3 的新特色： Phar</title>
	<description><![CDATA[
			註：以下程式我並沒有實作過，只是先分享一下給大家。
PHP 5.3 帶來很多有趣的特色，其中一個就是可以把你的 Library 打包成 phar 格式，並透過 require 敘述來引用裡面的程式碼。
首先你可以用 PHP 5.3 的新類別 Phar 來打包你想要的程式碼 (通常是類別檔案) ：
&lt;?php
$phar = new Phar('My.phar', 0, 'My.phar'); // 建立 My.phar 檔案
$phar-&gt;buildFromDirectory(
    dirname(__FILE__) . '/My', '/\.php$/'
); // 打包所有 My 目錄下的 php 檔案
$phar-&gt;compressFiles( Phar::GZ ); // 以 GZ 格式壓縮
$phar-&gt;stopBuffering(); // 壓縮完成，寫入 phar 檔
然後你可以整包引入：
require 'My.phar';
也可以單獨引入其中的某支檔案：
require 'phar://My.phar/src/Test.php';
就連 PHPUnit 3.3 也試用 Phar 來打包囉了！ 
那麼效能呢？據 Jan Schneider 的消息指出， PHP 的開發團隊已經把這個功能的效能調整到接近 native PHP 的執行進度了！
很酷吧？期待 PHP 5.3 的來臨吧！ 
參考 

 Friday afternoon toying: eZ Components as phar


		]]>
	</description>
	<content:encoded><![CDATA[
			<p class="note">註：以下程式我並沒有實作過，只是先分享一下給大家。</p>
<p>PHP 5.3 帶來很多有趣的特色，其中一個就是可以把你的 Library 打包成 phar 格式，並透過 require 敘述來引用裡面的程式碼。</p>
<p>首先你可以用 PHP 5.3 的新類別 Phar 來打包你想要的程式碼 (通常是類別檔案) ：</p>
<pre><code>&lt;?php
$phar = new Phar('My.phar', 0, 'My.phar'); // 建立 My.phar 檔案
$phar-&gt;buildFromDirectory(
    dirname(__FILE__) . '/My', '/\.php$/'
); // 打包所有 My 目錄下的 php 檔案
$phar-&gt;compressFiles( Phar::GZ ); // 以 GZ 格式壓縮
$phar-&gt;stopBuffering(); // 壓縮完成，寫入 phar 檔</code></pre>
<p>然後你可以整包引入：</p>
<pre><code>require 'My.phar';</code></pre>
<p>也可以單獨引入其中的某支檔案：</p>
<pre><code>require 'phar://My.phar/src/Test.php';</code></pre>
<p>就連 <a href="http://www.phpunit.de/">PHPUnit 3.3</a> 也<a href="http://sebastian-bergmann.de/archives/799-Phar.html">試用 Phar 來打包</a>囉了！ </p>
<p>那麼效能呢？據 Jan Schneider 的<a href="http://blog.stuartherbert.com/php/2008/06/29/where-are-the-benchmarks-for-phar/">消息</a>指出， PHP 的開發團隊已經把這個功能的效能調整到接近 native PHP 的執行進度了！</p>
<p>很酷吧？期待 PHP 5.3 的來臨吧！ </p>
<h2>參考 </h2>
<ul>
<li> <a href="http://derickrethans.nl/friday_afternoon_toying_ez_components_as_phar.php">Friday afternoon toying: eZ Components as phar</a></li>
</ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/6247655.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/6247655.html</guid>
	<category> PHP</category>
	<pubDate>Mon, 30 Jun 2008 10:08:45 +0800</pubDate>
</item>
<item>
	<title>[PHP] 在 PHP5 中實作 AOP 的概念</title>
	<description><![CDATA[
			這篇積在我電腦裡很久了，一直沒公開...這次趁著要幫我的 Library 加料，順便拿出來分享一下心得。 
什麼是 AOP
 AOP 全名為 Aspect-Oriented Programming ，基本的觀念可以參考良葛格的 AOP 入門：

從代理機制初探 AOP
動態代理
AOP 觀念與術語

這裡我簡單提一下 AOP 的基本想法：
假設當我們呼叫物件的某些方法 (或是業務流程) 之後，會想要把相關的資訊記錄到 log 檔裡，我們也許會這樣寫：
&lt;?php
/**
 * Test
 */
class Test
{
    /**
     * 某個方法
     */
    public function doSomething()
    {
        // 建立 Log 物件
        $logger = new Log();

        // 寫入前置 Log
        $logger-&gt;save('before do something.');

        // 主要的動作
        // ...

        // 寫入 Log
        $logger-&gt;save('before do something.');
    }
}
可是如果今天這個記錄 log 的這個動作只是臨時的，或是在未來可能會需要再加入不同的動作時 (例如寄信) ，難道我們還要在原有方法的程式碼裡修修改改嗎？有沒有什麼方式能協助我們動態地把記錄的動作插在原有動作之後呢？
AOP 就是從這個角度所延伸出來的一種觀念，它能協助我們在不侵入原有類別程式碼的狀況下，動態地為類別方法新增額外的權責；簡單來說， AOP 主要的目的就是切入類別原有方法執行之前或之後，並安插我們想要執行的動作。
註： IT 界似乎很喜歡發明深奧的名詞來詮釋一個簡單的概念，然後像我這樣不學無術的開發者就常被唬得一楞一楞的。
AOP 和 Decorator 
先介紹幾篇實作 AOP 的文章：

AOP for jQuery
Aspect Oriented Programming in PHP as a contrast to other languages.
Bunny Aspects
More on Aspect Oriented PHP
在PHP里利用魔术方法实现准AOP
AOP在PHP中的实现方式
Class: AOP Library for PHP

其實一開始我以為 AOP 和 Decorator 模式在 PHP 上的實作方式是差不多的，不過實際上還有是些許的差別。
一般在 Decorator 模式中，具體類別和 Wrapper 類別都會有個共同的祖先，亦即一個抽象類別或介面，因此所產生出來的物件對 Client 程式來說，其抽象型態可以說是一樣的。
但是在 AOP in PHP 中，我們必須透過一個代理類別來切入原有的類別方法裡，雖然這個代理類別也能夠提供原有類別中的所有方法，但是實際上它卻已經失去了與原有類別所擁有的抽象型態了。
用 PHP 實作 AOP
首先我們來看看還沒有切入任何事件的目標類別：
&lt;?php
/**
 * Test class
 *
 */
class TestClass
{
    /**
     * Method 1
     *
     * @param string $message
     */
    public function method1($message)
    {
        echo &quot;\n&quot;, __METHOD__, &quot;:\n&quot;, $message, &quot;\n&quot;;
    }

    /**
     * Method 2
     *
     * @return int
     */
    public function method2()
    {
        echo &quot;\n&quot;, __METHOD__, &quot;:\n&quot;;
        return rand(1, 10);
    }

    /**
     * Method 3
     *
     * @throws Exception
     */
    public function method3()
    {
        echo &quot;\n&quot;, __METHOD__, &quot;:\n&quot;;
        throw new Exception('Test Exception.');
    }
}
這個類別提供了三個方法，其中 method1 和 method2 只是簡單的顯示資料而已，而 method3 則會丟出一個異常。
另外我們需要一個 Log 類別：
&lt;?php
/**
 * Log
 *
 */
class Log
{
    /**
     * log message
     *
     * @param string $message
     */
    public function save($message)
    {
        echo $message, &quot;\n&quot;;
    }
}
這個 Log 類別只提供一個 save() 方法，以顯示 log 訊息。 
現在我們要完成的目標如下：


在 method1 執行前呼叫 Log::save() 。


在 method2 執行後呼叫 Log::save() 。


在 method3 發生異常時呼叫 Log::save() 。 


這裡我用很簡單的方式來做，那就是直接使用一個 Aspect 類別：
&lt;?php
/**
 * Aspect
 *
 */
class Aspect
{
    /**
     * Name of target class
     *
     * @var string
     */
    private $_className = null;

    /**
     * Target object
     *
     * @var object
     */
    private $_target = null;

    /**
     * Event callback
     *
     * @var array
     */
    private $_eventCallbacks = array();

    /**
     * Add object
     *
     * @param object $target
     * @return Aspect
     */
    public static function addObject($target)
    {
        return new Aspect($target);
    }

    /**
     * Contructor
     *
     * @param object $target
     */
    public function __construct($target)
    {
        if (is_object($target)) {
            $this-&gt;_target = $target;
            $this-&gt;_className = get_class($this-&gt;_target);
        }
    }

    /**
     * Register event
     *
     * @param string $eventName
     * @param string $methodName
     * @param callback $callback
     */
    private function _registerEvent($eventName, $methodName, $callback, $args)
    {
        if (!isset($this-&gt;_eventCallbacks[$methodName])) {
            $this-&gt;_eventCallbacks[$methodName] = array();
        }

        if (!is_callable(array($this-&gt;_target, $methodName))) {
            throw new Exception(get_class($this-&gt;_target) . '::' . $methodName . ' is not exists.');
        }

        if (is_callable($callback)) {
            $this-&gt;_eventCallbacks[$methodName][$eventName] = array($callback, $args);
        } else {
            $callbackName = Aspect::getCallbackName($callback);
            throw new Exception($callbackName . ' is not callable.');
        }
    }

    /**
     * Register 'before' handler
     *
     * @param string $methodName
     * @param callback $callback
     */
    public function before($methodName, $callback, $args = array())
    {
        $this-&gt;_registerEvent('before', $methodName, $callback, (array) $args);
    }

    /**
     * Register 'after' handler
     *
     * @param string $methodName
     * @param callback $callback
     */
    public function after($methodName, $callback, $args = array())
    {
        $this-&gt;_registerEvent('after', $methodName, $callback, (array) $args);
    }

    /**
     * Register 'on catch exception' handler
     *
     * @param string $methodName
     * @param callback $callback
     */
    public function onCatchException($methodName, $callback, $args = array())
    {
        $this-&gt;_registerEvent('onCatchException', $methodName, $callback, (array) $args);
    }

    /**
     * Trigger event
     *
     * @param string $eventName
     */
    private function _trigger($eventName, $methodName, $target)
    {
        if (isset($this-&gt;_eventCallbacks[$methodName][$eventName])) {
            list($callback, $args) = $this-&gt;_eventCallbacks[$methodName][$eventName];
            $args[] = $target;
            call_user_func_array($callback, $args);
        }
    }

    /**
     * Execute method
     *
     * @param string $methodName
     * @param array $args
     * @return mixed
     */
    public function __call($methodName, $args)
    {
        if (is_callable(array($this-&gt;_target, $methodName))) {
            try {
                $this-&gt;_trigger('before', $methodName, $this-&gt;_target);
                $result = call_user_func_array(array($this-&gt;_target, $methodName), $args);
                $this-&gt;_trigger('after', $methodName, $this-&gt;_target);
                return $result ? $result : null;
            } catch (Exception $e) {
                $this-&gt;_trigger('onCatchException', $methodName, $e);
                throw $e;
            }
        } else {
            throw new Exception(&quot;Call to undefined method {$this-&gt;_className}::$methodName.&quot;);
        }
    }

    /**
     * Get name of callback
     *
     * @param callback $callback
     * @return string
     */
    public static function getCallbackName($callback)
    {
        $className  = '';
        $methodName = '';

        if (is_array($callback) &amp;&amp; 2 == count($callback)) {
            if (is_object($callback[0])) {
                $className = get_class($callback[0]);
            } else {
                $className = (string) $callback[0];
            }
            $methodName = (string) $callback[1];
        } elseif (is_string($callback)) {
            $methodName = $callback;
        }

        return $className . (($className) ? '::' : '') . $methodName;
    }
}
這個類別有點小長，簡單說明如下：


 我們利用 Aspect::addObject() 方法來指定要被切入的物件； addObject() 方法會回傳一個透明的 Aspect 物件。


利用 before 、 after 和 onCatchException 三個方法來指定切入的時機，它們會呼叫 _registerEvent() 方法來註冊要執行的回呼函式 (callback) 。


執行原來被切入物件的方法，這時會觸動 Aspect 的 __call() 方法，並在指定的切入時機呼叫 _trigger() 方法來執行我們所切入的回呼函式。 


先來看看還沒有使用 AOP 前，我們對 TestClass 類別的測試：
&lt;?php
require_once 'TestClass.php';

$test = new TestClass();

/* @var $test TestClass */
echo &quot;=======\n&quot;;
$test-&gt;method1('abc');
echo &quot;=======\n&quot;;
echo $test-&gt;method2(), &quot;\n&quot;;
echo &quot;=======\n&quot;;
$test-&gt;method3();
echo &quot;=======\n&quot;;

/* 執行結果：
=======

TestClass::method1:
abc
=======

TestClass::method2:
2
=======

TestClass::method3:

Exception: Test Exception. in TestClass.php on line 38
*/
接下來我們利用 Aspect 類別來對 TestClass 物件的三個方法切入 Log::save() ：
&lt;?php
require_once 'Aspect.php';
require_once 'TestClass.php';
require_once 'Log.php';

$test = Aspect::addObject(new TestClass());
$logger = new Log();

$test-&gt;before('method1', array($logger, 'save'), 'Log saved (method1).');
$test-&gt;after('method2', array($logger, 'save'), 'Log saved (method2).');
$test-&gt;onCatchException('method3', array($logger, 'save'), 'Log saved (method3).');

/* @var $test TestClass */
echo &quot;=======\n&quot;;
$test-&gt;method1('abc');
echo &quot;=======\n&quot;;
echo $test-&gt;method2(), &quot;\n&quot;;
echo &quot;=======\n&quot;;
$test-&gt;method3();
echo &quot;=======\n&quot;;

/* 執行結果：
=======
Log saved (method1).

TestClass::method1:
abc
=======

TestClass::method2:
Log saved (method2).
8
=======

TestClass::method3:
Log saved (method3).

Exception: Test Exception. in TestClass.php on line 38
*/
結論
我們可以從範例看到， AOP 能幫我們在某類別的方法中插入一些額外的動作，同時又能不破壞原有類別的程式碼。而它與 Decorator 最大的不同是， Decorator 必須用很多小類別來完成相同的動作，但是 AOP 則透過 PHP 的動態特性解決了這個問題。
當然 AOP 也不是萬靈丹，像在本文的實作裡它就不能接觸目標類別的非公開屬性。而之前也跟 Mark 聊了一下，其實 AOP 偏向於程式的整體設計，所以這裡的範例尚不能用於實戰之中，僅僅只是我個人一個概念的實作而已。
供大家參考看看吧。也歡迎一起討論~

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>這篇積在我電腦裡很久了，一直沒公開...這次趁著要幫我的 Library 加料，順便拿出來分享一下心得。 </p>
<h2>什麼是 AOP</h2>
<p> AOP 全名為 Aspect-Oriented Programming ，基本的觀念可以參考良葛格的 AOP 入門：</p>
<ul>
<li><span id="text145561"><a href="http://caterpillar.onlyfun.net/Gossip/SpringGossip/FromProxyToAOP.html" target="_blank">從代理機制初探 AOP</a></span></li>
<li><span><a href="http://caterpillar.onlyfun.net/Gossip/SpringGossip/DynamicProxy.html" target="_blank">動態代理</a></span></li>
<li><span><a href="http://caterpillar.onlyfun.net/Gossip/SpringGossip/AOPConcept.html" target="_blank">AOP 觀念與術語</a></span></li>
</ul>
<p>這裡我簡單提一下 AOP 的基本想法：</p>
<p>假設當我們呼叫物件的某些方法 (或是<strong>業務流程</strong>) 之後，會想要把相關的資訊記錄到 log 檔裡，我們也許會這樣寫：</p>
<pre><code>&lt;?php
/**
 * Test
 */
class Test
{
    /**
     * 某個方法
     */
    public function doSomething()
    {
        // 建立 Log 物件
        $logger = new Log();

        // 寫入前置 Log
        $logger-&gt;save('before do something.');

        // 主要的動作
        // ...

        // 寫入 Log
        $logger-&gt;save('before do something.');
    }
}</code></pre>
<p>可是如果今天這個記錄 log 的這個動作只是臨時的，或是在未來可能會需要再加入不同的動作時 (例如寄信) ，難道我們還要在原有方法的程式碼裡修修改改嗎？有沒有什麼方式能協助我們動態地把記錄的動作插在原有動作之後呢？</p>
<p>AOP 就是從這個角度所延伸出來的一種觀念，它能協助我們在不侵入原有類別程式碼的狀況下，動態地為類別方法新增額外的權責；簡單來說， AOP 主要的目的就是<strong>切入類別原有方法執行之前或之後，並安插我們想要執行的動作</strong>。</p>
<p class="note">註： IT 界似乎很喜歡發明深奧的名詞來詮釋一個簡單的概念，然後像我這樣不學無術的開發者就常被唬得一楞一楞的。</p>
<h2>AOP 和 Decorator </h2>
<p>先介紹幾篇實作 AOP 的文章：</p>
<ul>
<li><a href="http://racklin.blogspot.com/2007/08/aop-for-jquery.html">AOP for jQuery</a></li>
<li><a href="http://blog.jonnay.net/archives/637-Aspect-Oriented-Programming-in-PHP-as-a-contrast-to-other-languages..html" target="_blank">Aspect Oriented Programming in PHP as a contrast to other languages.</a></li>
<li><a href="http://wiki.jonnay.net/bunny/bunnyaspectsphp" target="_blank">Bunny Aspects</a></li>
<li><a href="http://jaxn.org/article/2004/10/16/more-on-aspect-oriented-php/" title="Permanent Link to 'More on Aspect Oriented PHP'" target="_blank" rel="bookmark">More on Aspect Oriented PHP</a></li>
<li><a href="http://hi.baidu.com/thinkinginlamp/blog/item/864a0ef46d93b86eddc474f3.html" target="_blank">在PHP里利用魔术方法实现准AOP</a></li>
<li><a href="http://sushener.spaces.live.com/blog/cns!BB54050A5CFAFCDD!546.entry">AOP在PHP中的实现方式</a></li>
<li><a href="http://www.phpclasses.org/browse/package/2633.html">Class: AOP Library for PHP</a></li>
</ul>
<p>其實一開始我以為 AOP 和 Decorator 模式在 PHP 上的實作方式是差不多的，不過實際上還有是些許的差別。</p>
<p>一般在 Decorator 模式中，具體類別和 Wrapper 類別都會有個共同的祖先，亦即一個抽象類別或介面，因此所產生出來的物件對 Client 程式來說，其抽象型態可以說是一樣的。</p>
<p>但是在 AOP in PHP 中，我們必須透過一個代理類別來切入原有的類別方法裡，雖然這個代理類別也能夠提供原有類別中的所有方法，但是實際上它卻已經失去了與原有類別所擁有的抽象型態了。</p>
<h2>用 PHP 實作 AOP</h2>
<p>首先我們來看看還沒有切入任何事件的目標類別：</p>
<pre><code>&lt;?php
/**
 * Test class
 *
 */
class TestClass
{
    /**
     * Method 1
     *
     * @param string $message
     */
    public function method1($message)
    {
        echo &quot;\n&quot;, __METHOD__, &quot;:\n&quot;, $message, &quot;\n&quot;;
    }

    /**
     * Method 2
     *
     * @return int
     */
    public function method2()
    {
        echo &quot;\n&quot;, __METHOD__, &quot;:\n&quot;;
        return rand(1, 10);
    }

    /**
     * Method 3
     *
     * @throws Exception
     */
    public function method3()
    {
        echo &quot;\n&quot;, __METHOD__, &quot;:\n&quot;;
        throw new Exception('Test Exception.');
    }
}</code></pre>
<p>這個類別提供了三個方法，其中 method1 和 method2 只是簡單的顯示資料而已，而 method3 則會丟出一個異常。</p>
<p>另外我們需要一個 Log 類別：</p>
<pre><code>&lt;?php
/**
 * Log
 *
 */
class Log
{
    /**
     * log message
     *
     * @param string $message
     */
    public function save($message)
    {
        echo $message, &quot;\n&quot;;
    }
}</code></pre>
<p>這個 Log 類別只提供一個 save() 方法，以顯示 log 訊息。 </p>
<p>現在我們要完成的目標如下：</p>
<ol>
<li>
<p>在 method1 執行前呼叫 Log::save() 。</p>
</li>
<li>
<p>在 method2 執行後呼叫 Log::save() 。</p>
</li>
<li>
<p>在 method3 發生異常時呼叫 Log::save() 。 </p>
</li>
</ol>
<p>這裡我用很簡單的方式來做，那就是直接使用一個 Aspect 類別：</p>
<pre><code>&lt;?php
/**
 * Aspect
 *
 */
class Aspect
{
    /**
     * Name of target class
     *
     * @var string
     */
    private $_className = null;

    /**
     * Target object
     *
     * @var object
     */
    private $_target = null;

    /**
     * Event callback
     *
     * @var array
     */
    private $_eventCallbacks = array();

    /**
     * Add object
     *
     * @param object $target
     * @return Aspect
     */
    public static function addObject($target)
    {
        return new Aspect($target);
    }

    /**
     * Contructor
     *
     * @param object $target
     */
    public function __construct($target)
    {
        if (is_object($target)) {
            $this-&gt;_target = $target;
            $this-&gt;_className = get_class($this-&gt;_target);
        }
    }

    /**
     * Register event
     *
     * @param string $eventName
     * @param string $methodName
     * @param callback $callback
     */
    private function _registerEvent($eventName, $methodName, $callback, $args)
    {
        if (!isset($this-&gt;_eventCallbacks[$methodName])) {
            $this-&gt;_eventCallbacks[$methodName] = array();
        }

        if (!is_callable(array($this-&gt;_target, $methodName))) {
            throw new Exception(get_class($this-&gt;_target) . '::' . $methodName . ' is not exists.');
        }

        if (is_callable($callback)) {
            $this-&gt;_eventCallbacks[$methodName][$eventName] = array($callback, $args);
        } else {
            $callbackName = Aspect::getCallbackName($callback);
            throw new Exception($callbackName . ' is not callable.');
        }
    }

    /**
     * Register 'before' handler
     *
     * @param string $methodName
     * @param callback $callback
     */
    public function before($methodName, $callback, $args = array())
    {
        $this-&gt;_registerEvent('before', $methodName, $callback, (array) $args);
    }

    /**
     * Register 'after' handler
     *
     * @param string $methodName
     * @param callback $callback
     */
    public function after($methodName, $callback, $args = array())
    {
        $this-&gt;_registerEvent('after', $methodName, $callback, (array) $args);
    }

    /**
     * Register 'on catch exception' handler
     *
     * @param string $methodName
     * @param callback $callback
     */
    public function onCatchException($methodName, $callback, $args = array())
    {
        $this-&gt;_registerEvent('onCatchException', $methodName, $callback, (array) $args);
    }

    /**
     * Trigger event
     *
     * @param string $eventName
     */
    private function _trigger($eventName, $methodName, $target)
    {
        if (isset($this-&gt;_eventCallbacks[$methodName][$eventName])) {
            list($callback, $args) = $this-&gt;_eventCallbacks[$methodName][$eventName];
            $args[] = $target;
            call_user_func_array($callback, $args);
        }
    }

    /**
     * Execute method
     *
     * @param string $methodName
     * @param array $args
     * @return mixed
     */
    public function __call($methodName, $args)
    {
        if (is_callable(array($this-&gt;_target, $methodName))) {
            try {
                $this-&gt;_trigger('before', $methodName, $this-&gt;_target);
                $result = call_user_func_array(array($this-&gt;_target, $methodName), $args);
                $this-&gt;_trigger('after', $methodName, $this-&gt;_target);
                return $result ? $result : null;
            } catch (Exception $e) {
                $this-&gt;_trigger('onCatchException', $methodName, $e);
                throw $e;
            }
        } else {
            throw new Exception(&quot;Call to undefined method {$this-&gt;_className}::$methodName.&quot;);
        }
    }

    /**
     * Get name of callback
     *
     * @param callback $callback
     * @return string
     */
    public static function getCallbackName($callback)
    {
        $className  = '';
        $methodName = '';

        if (is_array($callback) &amp;&amp; 2 == count($callback)) {
            if (is_object($callback[0])) {
                $className = get_class($callback[0]);
            } else {
                $className = (string) $callback[0];
            }
            $methodName = (string) $callback[1];
        } elseif (is_string($callback)) {
            $methodName = $callback;
        }

        return $className . (($className) ? '::' : '') . $methodName;
    }
}</code></pre>
<p>這個類別有點小長，簡單說明如下：</p>
<ol>
<li>
<p> 我們利用 Aspect::addObject() 方法來指定要被切入的物件； addObject() 方法會回傳一個透明的 Aspect 物件。</p>
</li>
<li>
<p>利用 before 、 after 和 onCatchException 三個方法來指定切入的時機，它們會呼叫 _registerEvent() 方法來註冊要執行的回呼函式 (callback) 。</p>
</li>
<li>
<p>執行原來被切入物件的方法，這時會觸動 Aspect 的 __call() 方法，並在指定的切入時機呼叫 _trigger() 方法來執行我們所切入的回呼函式。 </p>
</li>
</ol>
<p>先來看看還沒有使用 AOP 前，我們對 TestClass 類別的測試：</p>
<pre><code>&lt;?php
require_once 'TestClass.php';

$test = new TestClass();

/* @var $test TestClass */
echo &quot;=======\n&quot;;
$test-&gt;method1('abc');
echo &quot;=======\n&quot;;
echo $test-&gt;method2(), &quot;\n&quot;;
echo &quot;=======\n&quot;;
$test-&gt;method3();
echo &quot;=======\n&quot;;

/* 執行結果：
=======

TestClass::method1:
abc
=======

TestClass::method2:
2
=======

TestClass::method3:

Exception: Test Exception. in TestClass.php on line 38
*/</code></pre>
<p>接下來我們利用 Aspect 類別來對 TestClass 物件的三個方法切入 Log::save() ：</p>
<pre><code>&lt;?php
require_once 'Aspect.php';
require_once 'TestClass.php';
require_once 'Log.php';

$test = Aspect::addObject(new TestClass());
$logger = new Log();

$test-&gt;before('method1', array($logger, 'save'), 'Log saved (method1).');
$test-&gt;after('method2', array($logger, 'save'), 'Log saved (method2).');
$test-&gt;onCatchException('method3', array($logger, 'save'), 'Log saved (method3).');

/* @var $test TestClass */
echo &quot;=======\n&quot;;
$test-&gt;method1('abc');
echo &quot;=======\n&quot;;
echo $test-&gt;method2(), &quot;\n&quot;;
echo &quot;=======\n&quot;;
$test-&gt;method3();
echo &quot;=======\n&quot;;

/* 執行結果：
=======
Log saved (method1).

TestClass::method1:
abc
=======

TestClass::method2:
Log saved (method2).
8
=======

TestClass::method3:
Log saved (method3).

Exception: Test Exception. in TestClass.php on line 38
*/</code></pre>
<h2>結論</h2>
<p>我們可以從範例看到， AOP 能幫我們在某類別的方法中插入一些額外的動作，同時又能不破壞原有類別的程式碼。而它與 Decorator 最大的不同是， Decorator 必須用很多小類別來完成相同的動作，但是 AOP 則透過 PHP 的動態特性解決了這個問題。</p>
<p>當然 AOP 也不是萬靈丹，像在本文的實作裡它就不能接觸目標類別的非公開屬性。而之前也跟 <a href="http://blog.markplace.net/">Mark</a> 聊了一下，其實 AOP 偏向於程式的整體設計，所以這裡的範例尚不能用於實戰之中，僅僅只是我個人一個概念的實作而已。</p>
<p>供大家參考看看吧。也歡迎一起討論~</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/5860329.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/5860329.html</guid>
	<category> PHP</category>
	<pubDate>Mon, 14 Apr 2008 18:29:34 +0800</pubDate>
</item>
<item>
	<title>[PHP] PHP 密技： include 與 require</title>
	<description><![CDATA[
			可以接受回傳資料？
先調查一下，知道 include 或 require 可以取得回傳資料的請舉手... (眺望)
呃...不知道的朋友也不用煩惱，我來解釋一下。
如何回傳資料呢？假設現在有個 php 檔叫做 config.php ，內容如下：
&lt;?php
return array('123', '456');
咦？那邊有人說 return 放錯地方了？不不不， PHP 能接受這樣的寫法。
好，現在我們來證明 include 或 require 能取得 config.php 所 return 回來的資料。請建立一支 test.php ，其內容是：
$config = require 'config.php';
var_dump($config);
執行看看，是不是可以跑呀？
所以我們可以在某支 PHP 程式中 return 一個資料 (任何型態) ，然後在另一支 PHP 程式中用 include 或 require 來取得這個資料。 
把 require 放在參數裡 
什麼？這不是密技？不不不，密技在底下：
function test($config) {
    var_dump($config);
}
test(require 'config.php');
對！你沒看錯！直接把 require 放在函式的參數裡！
還沒完呢，再看：
class Test
{
    public function __construct($config)
    {
        var_dump($config);
    }
}
$a = new Test(require 'config.php');
連 new 建構子的參數都可以接受 require ！
所以只要能放變數的地方，都可以放 include 或 require ，例如：
if (require 'config.php') {
    var_dump(require 'config.php');
}

if ($config = require 'config.php') {
    var_dump($config);
}
而且不僅是 include 及 require ，連 include_once 和 require_once 都可以這麼做。
我在某篇文章發現這個密技以後，分享給辦公室裡的同事們；沒想到玩了 PHP 這麼多年的他們也沒看過這個方法，看來大家對 PHP 的瞭解需要更深入一點囉！
Scope 的問題 
接著我同事問了我一個問題：如果在參數使用 require 敘述，而且被 require 的 PHP 程式裡如果有定義全域變數的話，那麼這個變數在執行的 PHP 程式裡，它的 scope 在哪裡呢？
答案是：它還是全域。
怎麼說呢？現在我們在剛剛的 config.php 的 return 敘述前加上一行程式，如下：
&lt;?php
$data = '789'; // 加上這行
return array('123', '456');
然後在 test.php 裡的 Global 部份 (也就是不在函式或類別定義裡) 的任意處加入：
var_dump($data);
是不是也可以正確顯示 config.php 中 $data 變數所指定的內容呢？這就表示在參數中使用 require 不會影響全域變數的 scope 。
還有其他 include 或 require 的密技嗎？歡迎大家一起討論囉~
什麼！你早就會了？太好了！我們非常非常需要你！
		]]>
	</description>
	<content:encoded><![CDATA[
			<h2>可以接受回傳資料？</h2>
<p>先調查一下，知道 include 或 require 可以取得回傳資料的請舉手... (眺望)</p>
<p>呃...不知道的朋友也不用煩惱，我來解釋一下。</p>
<p>如何回傳資料呢？假設現在有個 php 檔叫做 config.php ，內容如下：</p>
<pre><code>&lt;?php
return array('123', '456');</code></pre>
<p>咦？那邊有人說 return 放錯地方了？不不不， PHP 能接受這樣的寫法。</p>
<p>好，現在我們來證明 include 或 require 能取得 config.php 所 return 回來的資料。請建立一支 test.php ，其內容是：</p>
<pre><code>$config = require 'config.php';
var_dump($config);</code></pre>
<p>執行看看，是不是可以跑呀？</p>
<p>所以我們可以在某支 PHP 程式中 return 一個資料 (任何型態) ，然後在另一支 PHP 程式中用 include 或 require 來取得這個資料。 </p>
<h2>把 require 放在參數裡 </h2>
<p>什麼？這不是密技？不不不，密技在底下：</p>
<pre><code>function test($config) {
    var_dump($config);
}
test(require 'config.php');</code></pre>
<p>對！你沒看錯！直接把 require 放在函式的參數裡！</p>
<p>還沒完呢，再看：</p>
<pre><code>class Test
{
    public function __construct($config)
    {
        var_dump($config);
    }
}
$a = new Test(require 'config.php');</code></pre>
<p>連 new 建構子的參數都可以接受 require ！</p>
<p>所以只要能放變數的地方，都可以放 include 或 require ，例如：</p>
<pre><code>if (require 'config.php') {
    var_dump(require 'config.php');
}

if ($config = require 'config.php') {
    var_dump($config);
}</code></pre>
<p>而且不僅是 include 及 require ，連 include_once 和 require_once 都可以這麼做。</p>
<p>我在<a href="http://blog.astrumfutura.com/archives/340-The-Zend-Framework,-Dependency-Injection-and-Zend_Di.html">某篇文章</a>發現這個密技以後，分享給辦公室裡的同事們；沒想到玩了 PHP 這麼多年的他們也沒看過這個方法，看來大家對 PHP 的瞭解需要更深入一點囉！</p>
<h2>Scope 的問題 </h2>
<p>接著我同事問了我一個問題：如果在參數使用 require 敘述，而且被 require 的 PHP 程式裡如果有定義全域變數的話，那麼這個變數在執行的 PHP 程式裡，它的 scope 在哪裡呢？</p>
<p>答案是：它還是全域。</p>
<p>怎麼說呢？現在我們在剛剛的 config.php 的 return 敘述前加上一行程式，如下：</p>
<pre><code>&lt;?php
<strong>$data = '789';</strong> // 加上這行
return array('123', '456');</code></pre>
<p>然後在 test.php 裡的 Global 部份 (也就是不在函式或類別定義裡) 的任意處加入：</p>
<pre><code>var_dump($data);</code></pre>
<p>是不是也可以正確顯示 config.php 中 $data 變數所指定的內容呢？這就表示在參數中使用 require 不會影響全域變數的 scope 。</p>
<p>還有其他 include 或 require 的密技嗎？歡迎大家一起討論囉~</p>
<p class="note">什麼！你早就會了？太好了！<a href="http://blog.roodo.com/jaceju/archives/3282383.html">我們非常非常需要你！</a></p>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/5579811.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/5579811.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 22 Feb 2008 21:00:00 +0800</pubDate>
</item>
<item>
	<title>[PHP] mysql_query 的記憶體使用與分頁方式</title>
	<description><![CDATA[
			說明
這個實驗主要是探討在 TWPUG 上的這篇 FIEND 寫的： [原創] [分享] 小弟寫的 cakephp 換頁 排序 功能 (第一版) 。
幾個實驗重點如下：


FIEND 提到兩次 Query 不是一個好方式，他的做法是用一次 Query 配合 while + mysql_result 就能做到分頁效果。


另外 shirock 從 PHP 原始碼的部份解釋 PHP 和 MySQL 抓資料後的處理方式，但 FIEND 卻說「用屁股想都知道 PHP 不可能把 QUERY 結果 全部拉回 PHP 端記憶體」。

還有 shirock 提到：「參考文章中已經很明白指出 mysql_query 跳過 PHP 內建記憶體配置機制，而直接使用 mysql C library 的函數儲存資料在 PHP 程序這端。而 memory_limit 只會管制到 PHP 內建記憶體配置機制的使用上限。所以 mysql_query 查詢大量資料時，不會受到 memory_limit 的限制。」 

基本上我從來不知道屁股可以用來思考，所以我還是要實事求是，用 FIEND 的方法實驗一次。
註：不過我老是在上廁所時想到一些靈感...Orz
環境

Windows XP
PHP 5.2.5
MySQL 5.0.45
memory_limit = 16M (in php.ini)

另外我準備了一個資料庫，裡面包含了四個資料表：


資料表 
筆數
硬碟空間


r1000
一千筆
75KB


r10000
一萬筆
743KB


r100000
十萬筆
7,422KB


r1000000
一百萬筆
74,219KB


資料表欄位為一個 id 欄位和一個 value 欄位；而 value 欄位為 varchar(64) ，其內容存的是兩個隨機的 md5 函式結果所組合的字串。可以用以下程式產生：
&lt;?php
echo &quot;CREATE DATABASE `page_test`;\n&quot;;
echo &quot;USE `page_test`;\n&quot;;

foreach (array(1000, 10000, 100000, 1000000) as $r) {
    $sql = &lt;&lt;&lt;SQL
CREATE TABLE IF NOT EXISTS `r$r` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `value` varchar(64) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM;
SQL;
    echo $sql, &quot;\n&quot;;
    for ($i = 1; $i &lt;= $r; $i ++) {
        $value = md5(rand(0, 9999)) . md5(rand(0, 9999));
        echo &quot;INSERT INTO `r$r` (`value`) VALUES ('$value');\n&quot;;
    }
}
程式
程式部份很簡單，就是按照 FIEND 說的步驟來寫的。只是我這裡改用 CLI 模式執行，以避掉 Apache 的影響。 
&lt;?php
echo ini_get('memory_limit'), &quot;\n&quot;; // 16M
echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;Start.\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

$link = mysql_connect('localhost', 'username', 'password');
mysql_select_db('page_test', $link);

$result = mysql_query('SELECT * FROM r1000000', $link);

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_query\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

$count  = mysql_num_rows($result);
echo 'count: ', $count, &quot;\n&quot;;

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_num_rows\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

$start = rand(0, $count - 1);
$end   = $start + 10;
$i     = $start;

echo 'start: ' . $start, &quot;\n&quot;;
echo 'end: ' . $end, &quot;\n&quot;;

echo &quot;\n&quot;;
while ($id = mysql_result($result, $i, 'id')) {
   echo $i, ': ', $id, &quot;\n&quot;;
   $i ++;
   if ($i &gt;= $end || $i &gt;= $count) break;
}

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;while &amp; mysql_result\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

mysql_free_result($result);

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_free_result\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

mysql_close($link);

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_close\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);
而記憶體的觀察我是用 Windows 的工作管理員，然後查看 php.exe 所使用的記憶體大小。在什麼都沒有執行的狀況下， php.exe 會佔用掉約 8MB 的記憶體 (在我的環境下) 。 
結果如下 (每項執行 5 次後再取平均值) ：


資料表
程式啟動
mysql_query
mysql_num_rows
while &amp; mysql_result
mysql_free_result
mysql_close


r1000
8,196KB
8,592KB
8,596KB
8,656KB
8,568KB
8,556KB


r10000
8,196KB
9,496KB
9,500KB
9,560KB
8,592KB
8,580KB


r100000
8,192KB
18,840KB
18,844KB
18,904KB
8,584KB
8,596KB


r1000000
8,192KB
110,684KB
110,688KB
110,748KB
8,796KB
8,784KB


然後我比較 mysql_query 用掉的記憶體和原來資料表使用的硬碟空間： 


資料表
mysql_query
硬碟空間


r1000
396KB
75KB


r10000
1,300KB
743KB


r100000
10,648KB
7,422KB


r1000000
102,492KB
74,219KB


很明顯地 mysql_query 所得到的 resource 佔的記憶體空間比 MySQL 使用的硬碟大小還多，這證明了 mysql_query 是有把資料內容抓到 PHP 這邊來；至於為什麼 MySQL 的反而比較小，我想這應該是 MySQL 將資料做壓縮的關係。
補充：我上面在 MySQL 壓縮的部份沒有任何根據，應該是錯誤的推論；因此我想就以 normansu 給我的說明為準： 

normansu 提到： 
應該不是.
執行 mysql_store_result 的時候, 
在 result 和每一筆 record 都會多一個 Header 的空間,
大小不一定(看 field count).

所以使用的記憶體會比實際 mysql table 大.
在 source 中沒有看到任何 compress 的動作.


mysql 的這個流程讓我嚇一跳,
以往大部份用的是 mssql 和 oracle,
在 client 和 server 間的 data cache 機制都做得比較好,
看起來 mysql 像是把結果算出來後就直接全部丟出來.

所以使用 mysql 要比用 mssql 或oracle 要來得更小心一點.


然後由於在上面的實驗裡我已經將 php.ini 的 memory_limit 設為 16M ，也用過 php -i 檢查過了。但在執行一百萬筆測試時，卻沒有受到任何影響，因此也證明了 shirock 說的「所以 mysql_query 查詢大量資料時，不會受到 memory_limit 的限制。」 
結論
從上面的實驗可以看到一次 Query 並取得資料總筆數雖是可行的，但這個前提是建立在 mysql_query 已經把資料內容全部放到 php.exe 的記憶體中。除非我誤解了 FIEND 的意思，不然他的作法看起來實在不適用於他所說的「存取大量資料的環境」。 
所以一般常見的做法是採用就是 tokimeki 提到的兩次 Query 的方式，第一次先利用 SQL 的 COUNT() 指令取得我們所需要的總筆數，第二次再配合 LIMIT 去取得我們所要的資料。不用 LIMIT 的後果就是每當執行一次 script ，我們就要冒著記憶體使用量爆增的後果。
註：雖然 MySQL 有 Query Cache ，但對 php 端已經爆增的記憶體也於事無補了。
而我也贊成 tokimeki 說的：「另外之二，假設內容資料是非常龐大的，且必須利用查詢內容作某些運算（例如：矩陣運算之類的），那麼這樣的應用不該由PHP程式來完成，應由其他的方式來作計算（例如：資料庫作OLAP或是Server上某個用C/C++寫的程式定期跑），Web這邊只做顯示以及計算排程即可。」
其他不想多說了，被某人看不起也不是一天兩天的事了。我自知自己還有很多東西要學，而這些還有望其他高手前輩們給予我指教。
不過最後這個實驗也證明一件事：屁股不是用來想事情的。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<h2>說明</h2>
<p>這個實驗主要是探討在 TWPUG 上的這篇 FIEND 寫的： <a href="http://twpug.net/modules/newbb/viewtopic.php?topic_id=3094&amp;forum=35">[原創] [分享] 小弟寫的 cakephp 換頁 排序 功能 (第一版)</a> 。</p>
<p>幾個實驗重點如下：</p>
<ul>
<li>
<p>FIEND 提到兩次 Query 不是一個好方式，他的做法是用一次 Query 配合 while + mysql_result 就能做到分頁效果。</p>
</li>
<li>
<p>另外 shirock 從 PHP 原始碼的部份<a href="http://blog.roodo.com/rocksaying/archives/4986803.html">解釋 PHP 和 MySQL 抓資料後的處理方式</a>，但 FIEND 卻說「<strong><a href="http://twpug.net/modules/newbb/viewtopic.php?post_id=11749#forumpost11749">用屁股想都知道 PHP 不可能把 QUERY 結果 全部拉回 PHP 端記憶體</a></strong>」。</p>
</li>
<li>還有 shirock 提到：「參考文章中已經很明白指出 mysql_query 跳過 PHP 內建記憶體配置機制，而直接使用 mysql C library 的函數儲存資料在 PHP 程序這端。而 memory_limit 只會管制到 PHP 內建記憶體配置機制的使用上限。所以 mysql_query 查詢大量資料時，不會受到 memory_limit 的限制。」 </li>
</ul>
<p>基本上我從來不知道屁股可以用來思考，所以我還是要實事求是，用 FIEND 的方法實驗一次。</p>
<p class="note">註：不過我老是在上廁所時想到一些靈感...Orz</p>
<h2>環境</h2>
<ul>
<li>Windows XP</li>
<li>PHP 5.2.5</li>
<li>MySQL 5.0.45</li>
<li>memory_limit = 16M (in php.ini)</li>
</ul>
<p>另外我準備了一個資料庫，裡面包含了四個資料表：</p>
<table border="1" cellspacing="1" cellpadding="3" summary="測試用資料表">
<tr>
<th>資料表 </th>
<th>筆數</th>
<th>硬碟空間</th>
</tr>
<tr>
<td align="right">r1000</td>
<td align="right">一千筆</td>
<td align="right">75KB</td>
</tr>
<tr>
<td align="right">r10000</td>
<td align="right">一萬筆</td>
<td align="right">743KB</td>
</tr>
<tr>
<td align="right">r100000</td>
<td align="right">十萬筆</td>
<td align="right">7,422KB</td>
</tr>
<tr>
<td align="right">r1000000</td>
<td align="right">一百萬筆</td>
<td align="right">74,219KB</td>
</tr>
</table>
<p>資料表欄位為一個 id 欄位和一個 value 欄位；而 value 欄位為 varchar(64) ，其內容存的是兩個隨機的 md5 函式結果所組合的字串。可以用以下程式產生：</p>
<pre><code>&lt;?php
echo &quot;CREATE DATABASE `page_test`;\n&quot;;
echo &quot;USE `page_test`;\n&quot;;

foreach (array(1000, 10000, 100000, 1000000) as $r) {
    $sql = &lt;&lt;&lt;SQL
CREATE TABLE IF NOT EXISTS `r$r` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `value` varchar(64) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM;
SQL;
    echo $sql, &quot;\n&quot;;
    for ($i = 1; $i &lt;= $r; $i ++) {
        $value = md5(rand(0, 9999)) . md5(rand(0, 9999));
        echo &quot;INSERT INTO `r$r` (`value`) VALUES ('$value');\n&quot;;
    }
}</code></pre>
<h2>程式</h2>
<p>程式部份很簡單，就是按照 FIEND 說的步驟來寫的。只是我這裡改用 CLI 模式執行，以避掉 Apache 的影響。 </p>
<pre><code>&lt;?php
echo ini_get('memory_limit'), &quot;\n&quot;; // 16M
echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;Start.\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

$link = mysql_connect('localhost', 'username', 'password');
mysql_select_db('page_test', $link);

$result = mysql_query('SELECT * FROM r1000000', $link);

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_query\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

$count  = mysql_num_rows($result);
echo 'count: ', $count, &quot;\n&quot;;

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_num_rows\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

$start = rand(0, $count - 1);
$end   = $start + 10;
$i     = $start;

echo 'start: ' . $start, &quot;\n&quot;;
echo 'end: ' . $end, &quot;\n&quot;;

echo &quot;\n&quot;;
while ($id = mysql_result($result, $i, 'id')) {
   echo $i, ': ', $id, &quot;\n&quot;;
   $i ++;
   if ($i &gt;= $end || $i &gt;= $count) break;
}

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;while &amp; mysql_result\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

mysql_free_result($result);

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_free_result\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);

mysql_close($link);

echo &quot;\n&quot;;
echo &quot;========================\n&quot;;
echo &quot;mysql_close\n&quot;;
echo &quot;========================\n&quot;;
sleep(10);</code></pre>
<p>而記憶體的觀察我是用 Windows 的工作管理員，然後查看 php.exe 所使用的記憶體大小。在什麼都沒有執行的狀況下， php.exe 會佔用掉約 8MB 的記憶體 (在我的環境下) 。 </p>
<p>結果如下 (每項執行 5 次後再取平均值) ：</p>
<table border="1" cellspacing="1" cellpadding="3" summary="程式執行時的記憶體用量比較">
<tr>
<th>資料表</th>
<th>程式啟動</th>
<th>mysql_query</th>
<th>mysql_num_rows</th>
<th>while &amp; mysql_result</th>
<th>mysql_free_result</th>
<th>mysql_close</th>
</tr>
<tr>
<td align="right">r1000</td>
<td align="right">8,196KB</td>
<td align="right">8,592KB</td>
<td align="right">8,596KB</td>
<td align="right">8,656KB</td>
<td align="right">8,568KB</td>
<td align="right">8,556KB</td>
</tr>
<tr>
<td align="right">r10000</td>
<td align="right">8,196KB</td>
<td align="right">9,496KB</td>
<td align="right">9,500KB</td>
<td align="right">9,560KB</td>
<td align="right">8,592KB</td>
<td align="right">8,580KB</td>
</tr>
<tr>
<td align="right">r100000</td>
<td align="right">8,192KB</td>
<td align="right">18,840KB</td>
<td align="right">18,844KB</td>
<td align="right">18,904KB</td>
<td align="right">8,584KB</td>
<td align="right">8,596KB</td>
</tr>
<tr>
<td align="right">r1000000</td>
<td align="right">8,192KB</td>
<td align="right">110,684KB</td>
<td align="right">110,688KB</td>
<td align="right">110,748KB</td>
<td align="right">8,796KB</td>
<td align="right">8,784KB</td>
</tr>
</table>
<p>然後我比較 mysql_query 用掉的記憶體和原來資料表使用的硬碟空間： </p>
<table border="1" cellspacing="1" cellpadding="3" summary="比較 mysql_query 用掉的記憶體和原來資料表使用的硬碟空間">
<tr>
<th>資料表</th>
<th>mysql_query</th>
<th>硬碟空間</th>
</tr>
<tr>
<td align="right">r1000</td>
<td align="right">396KB</td>
<td align="right">75KB</td>
</tr>
<tr>
<td align="right">r10000</td>
<td align="right">1,300KB</td>
<td align="right">743KB</td>
</tr>
<tr>
<td align="right">r100000</td>
<td align="right">10,648KB</td>
<td align="right">7,422KB</td>
</tr>
<tr>
<td align="right">r1000000</td>
<td align="right">102,492KB</td>
<td align="right">74,219KB</td>
</tr>
</table>
<p>很明顯地 mysql_query 所得到的 resource 佔的記憶體空間比 MySQL 使用的硬碟大小還多，這證明了 <strong>mysql_query 是有把資料內容抓到 PHP 這邊來</strong><del>；至於為什麼 MySQL 的反而比較小，我想這應該是 MySQL 將資料做壓縮的關係</del>。</p>
<p><strong>補充：</strong>我上面在 MySQL 壓縮的部份沒有任何根據，應該是錯誤的推論；因此我想就以 normansu 給我的說明為準： </p>
<blockquote>
<p><a href="http://twpug.net/modules/newbb/viewtopic.php?post_id=11784#forumpost11784">normansu 提到</a>： </p>
<p>應該不是.<br />
執行 mysql_store_result 的時候, <br />
在 result 和每一筆 record 都會多一個 Header 的空間,<br />
大小不一定(看 field count).<br />
<br />
所以使用的記憶體會比實際 mysql table 大.<br />
在 source 中沒有看到任何 compress 的動作.<br />
<br />
<br />
mysql 的這個流程讓我嚇一跳,<br />
以往大部份用的是 mssql 和 oracle,<br />
在 client 和 server 間的 data cache 機制都做得比較好,<br />
看起來 mysql 像是把結果算出來後就直接全部丟出來.<br />
<br />
所以使用 mysql 要比用 mssql 或oracle 要來得更小心一點.
</p>
</blockquote>
<p>然後由於在上面的實驗裡我已經將 php.ini 的 memory_limit 設為 16M ，也用過 php -i 檢查過了。但在執行一百萬筆測試時，卻沒有受到任何影響，因此也證明了 shirock 說的「<strong>所以 mysql_query 查詢大量資料時，不會受到 memory_limit 的限制。</strong>」 </p>
<h2>結論</h2>
<p>從上面的實驗可以看到一次 Query 並取得資料總筆數雖是可行的，但這個<strong>前提是建立在 mysql_query 已經把資料內容全部放到 php.exe 的記憶體中</strong>。除非我誤解了 FIEND 的意思，不然他的作法看起來實在不適用於他所說的「存取大量資料的環境」。 </p>
<p>所以一般常見的做法是採用就是 tokimeki 提到的<a href="http://twpug.net/modules/newbb/viewtopic.php?post_id=11671#forumpost11671">兩次 Query 的方式</a>，第一次先利用 SQL 的 COUNT() 指令取得我們所需要的總筆數，第二次再配合 LIMIT 去取得我們所要的資料。不用 LIMIT 的後果就是每當執行一次 script ，我們就要冒著記憶體使用量爆增的後果。</p>
<p class="note">註：雖然 MySQL 有 <a href="http://www.tblog.com.cn/index.php/archives/659">Query Cache</a> ，但對 php 端已經爆增的記憶體也於事無補了。</p>
<p>而我也贊成 tokimeki 說的：「另外之二，假設內容資料是非常龐大的，且必須利用查詢內容作某些運算（例如：矩陣運算之類的），那麼這樣的應用不該由PHP程式來完成，應由其他的方式來作計算（例如：資料庫作OLAP或是Server上某個用C/C++寫的程式定期跑），Web這邊只做顯示以及計算排程即可。」</p>
<p>其他不想多說了，被某人看不起也不是一天兩天的事了。我自知自己還有很多東西要學，而這些還有望其他高手前輩們給予我指教。</p>
<p>不過最後這個實驗也證明一件事：屁股不是用來想事情的。 </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4991595.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4991595.html</guid>
	<category> PHP</category>
	<pubDate>Wed, 16 Jan 2008 16:21:01 +0800</pubDate>
</item>
<item>
	<title>[PHP] 交換兩個變數 (不使用 tmp 變數) 程式寫法</title>
	<description><![CDATA[
			在宗董的 Blog 看到這篇：交換兩個變數 (不使用 tmp 變數) 程式寫法，本來想留言，不過宗董的 Blog 系統似乎有問題。
宗董的方法是這樣的：
$a ^= $b;
$b ^= $a;
$a ^= $b;
我是想說既然是用 PHP 了，就應該好好善用一下 PHP 的原生語法：
list($a, $b) = array($b, $a);
搞定~~
這個是從 PHP 程式設計專家必備手冊一書看來的。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>在宗董的 Blog 看到這篇：<a href="http://plog.longwin.com.tw/programming/2007/11/23/variable_swap_programming_2007">交換兩個變數 (不使用 tmp 變數) 程式寫法</a>，本來想留言，不過宗董的 Blog 系統似乎有問題。</p>
<p>宗董的方法是這樣的：</p>
<pre><code>$a ^= $b;
$b ^= $a;
$a ^= $b;</code></pre>
<p>我是想說既然是用 PHP 了，就應該好好善用一下 PHP 的原生語法：</p>
<pre><code>list($a, $b) = array($b, $a);</code></pre>
<p>搞定~~</p>
<p>這個是從 <a href="http://www.pearsoned.com.tw/chinese_show_title.asp?bkid=9867910672">PHP 程式設計專家必備手冊</a>一書看來的。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4528893.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4528893.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 23 Nov 2007 15:27:09 +0800</pubDate>
</item>
<item>
	<title>[PHP] 神奇的 $this</title>
	<description><![CDATA[
			今天發現了一個 PHP 5.2.4 的奇怪現象，查了官方手冊也沒發現有人特別提起 (也可能是我沒找到) 。
學過 PHP 物件導向的人都知道， $this 這個關鍵字是在生成一個物件後才能使用的。例如：
class Foo
{
    private $_foo = '_foo in class Foo.';

    public function test()
    {
        echo $this-&gt;_foo;
    }
}

$foo = new Foo();
$foo-&gt;test(); // _foo in class Foo.
而且 $this 在 Class 的程式碼裡代表的也是這個物件本身，在上例中即為 $foo 。
不過在 method 裡使用 $this 有個限制，那就是該 method 不能以 static 的方式來呼叫；也就是說，以下的執行方式是錯的：
Foo::test(); // Fatal error: Using $this when not in object context in xxx.php 
可是請看以下的程式碼：
&lt;?php

class Foo
{
    private $_foo = '_foo in class Foo.';

    public function test()
    {
        echo $this-&gt;_foo;
    }
}

class Bar
{
    public function test()
    {
        Foo::test();
    }
}

$b = new Bar();
$b-&gt;test(); // Notice: Undefined property:  Bar::$_foo in xxx.php
發現什麼問題了嗎？在 Bar::test() 裡我們竟然可以用 static 的方式呼叫 Foo::test() ！ 而且在 Foo::test() 裡的 $this-&gt;_foo 竟然變成了 Bar 類別的 $_foo 屬性！ 
至於這倒底是 PHP 的特色還是 Bug ？我也不知道，還望高手賜教。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>今天發現了一個 PHP 5.2.4 的奇怪現象，查了官方手冊也沒發現有人特別提起 (也可能是我沒找到) 。</p>
<p>學過 PHP 物件導向的人都知道， $this 這個關鍵字是在生成一個物件後才能使用的。例如：</p>
<pre><code>class Foo
{
    private $_foo = '_foo in class Foo.';

    public function test()
    {
        echo $this-&gt;_foo;
    }
}

$foo = new Foo();
$foo-&gt;test(); // _foo in class Foo.</code></pre>
<p>而且 $this 在 Class 的程式碼裡代表的也是這個物件本身，在上例中即為 $foo 。</p>
<p>不過在 method 裡使用 $this 有個限制，那就是該 method 不能以 static 的方式來呼叫；也就是說，以下的執行方式是錯的：</p>
<pre><code>Foo::test(); // Fatal error: Using $this when not in object context in xxx.php </code></pre>
<p>可是請看以下的程式碼：</p>
<pre><code>&lt;?php

class Foo
{
    private $_foo = '_foo in class Foo.';

    public function test()
    {
        echo $this-&gt;_foo;
    }
}

class Bar
{
    public function test()
    {
        Foo::test();
    }
}

$b = new Bar();
$b-&gt;test(); // Notice: Undefined property:  Bar::$_foo in xxx.php</code></pre>
<p>發現什麼問題了嗎？在 Bar::test() 裡我們竟然可以用 static 的方式呼叫 Foo::test() ！ 而且在 Foo::test() 裡的 $this-&gt;_foo 竟然變成了 Bar 類別的 $_foo 屬性！ </p>
<p>至於這倒底是 PHP 的特色還是 Bug ？我也不知道，還望高手賜教。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4365549.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4365549.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 26 Oct 2007 00:14:38 +0800</pubDate>
</item>
<item>
	<title>[PHP] PHP 5.2.4 發佈</title>
	<description><![CDATA[
			

PHP 5.2.4 Released
主要是修正了很多 Bug ， 我想等一陣子再更新好了。 


獵人261 連載再開!!!!  富樫義博 終於要畫 HunterXhunter 261了!!!
富奸終於要畫新的獵人了~~真是太感動了！！！ ( TT__TT ) 
什麼？這跟網站製作沒關係喔？因為我太高興了嗎...



		]]>
	</description>
	<content:encoded><![CDATA[
			<ul>
<li>
<p><a href="http://www.php.net/index.php#2007-08-30-1">PHP 5.2.4 Released</a></p>
<p>主要是修正了很多 Bug ， 我想等一陣子再更新好了。 </p>
</li>
<li>
<p><a href="http://ookkk.blogspot.com/2007/08/261-hunterxhunter-261.html">獵人261 連載再開!!!!  富樫義博 終於要畫 HunterXhunter 261了!!!</a></p>
<p>富奸終於要畫新的獵人了~~真是太感動了！！！ ( TT__TT ) </p>
<p>什麼？這跟網站製作沒關係喔？因為我太高興了嗎...</p>
</li>
</ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/4054959.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/4054959.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 31 Aug 2007 14:07:57 +0800</pubDate>
</item>
<item>
	<title>[PHP] 幾篇不錯的文章</title>
	<description><![CDATA[
			

Incredible Zend ZDE debugging trick for debugging CLI apps
用以下方式來 Debug PHP CLI 應用程式，我只能說作者真的很天才。
C:\&gt; set &quot;QUERY_STRING=start_debug=1&amp;debug_host=192.168.0.102&amp;debug_port=10000&amp;debug_stop=1&quot;
有機會應該來試試看才對。


AJAX and PHP End-to-End Debugging
參考上一篇文章的方式，這次用來 Debug Ajax ；也就是把上面的 QUERY_STRING 系統變數當做 Ajax 的 GET 參數。 


PHP: Arrays vs. Objects
又是一篇比較 PHP 陣列和物件效率的文章，我個人是認為效率相差不大的狀況下，應該挑選適合程序的方式來用，而不是固執於一種形式。


PHP Namespaces (Part 1: Basic usage &amp; gotchas)
這篇告訴你為什麼要用 Namespaces ，而 Mark 在中文化 dotProject 時也遇過同樣的問題。 


Namespaces FAQ
經典：

 Q: PHP 為什麼需要 Namespaces ？
A: 因為 PEAR_Form_Loader_Validate_Table_Element_Validator_Exception 實在是太 TMD 長了。 (嗯...這句是我瞎掰的 XD) 




		]]>
	</description>
	<content:encoded><![CDATA[
			<ul>
<li>
<p><a href="http://greg.chiaraquartet.net/archives/16-Incredible-Zend-ZDE-debugging-trick-for-debugging-CLI-apps.html">Incredible Zend ZDE debugging trick for debugging CLI apps</a></p>
<p>用以下方式來 Debug PHP CLI 應用程式，我只能說作者真的很天才。</p>
<pre><code>C:\&gt; set &quot;QUERY_STRING=start_debug=1&amp;debug_host=192.168.0.102&amp;debug_port=10000&amp;debug_stop=1&quot;</code></pre>
<p>有機會應該來試試看才對。</p>
</li>
<li>
<p><a href="http://pixelated-dreams.com/archives/313-AJAX-and-PHP-End-to-End-Debugging.html">AJAX and PHP End-to-End Debugging</a></p>
<p>參考上一篇文章的方式，這次用來 Debug Ajax ；也就是把上面的 QUERY_STRING 系統變數當做 Ajax 的 GET 參數。 </p>
</li>
<li>
<p><a href="http://www.rooftopsolutions.nl/article/148">PHP: Arrays vs. Objects</a></p>
<p>又是一篇比較 PHP 陣列和物件效率的文章，我個人是認為效率相差不大的狀況下，應該挑選適合程序的方式來用，而不是固執於一種形式。</p>
</li>
<li>
<p><a href="http://blog.agoraproduction.com/index.php?/archives/47-PHP-Namespaces-Part-1-Basic-usage-gotchas.html">PHP Namespaces (Part 1: Basic usage &amp; gotchas)</a></p>
<p>這篇告訴你為什麼要用 Namespaces ，而 Mark 在中文化 dotProject 時也遇過同樣的問題。 </p>
</li>
<li>
<p><a href="http://php100.wordpress.com/2007/08/17/namespaces-faq/">Namespaces FAQ</a></p>
<p>經典：</p>
<blockquote>
<p> Q: PHP 為什麼需要 Namespaces ？</p>
<p>A: 因為 PEAR_Form_Loader_Validate_Table_Element_Validator_Exception 實在是太 TMD 長了。 (嗯...這句是我瞎掰的 XD) </p>
</blockquote>
</li>
</ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3952367.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3952367.html</guid>
	<category> PHP</category>
	<pubDate>Sat, 18 Aug 2007 13:58:56 +0800</pubDate>
</item>
<item>
	<title>[轉載] Scraping Links With PHP</title>
	<description><![CDATA[
			剛剛看到一篇很有用的 PHP 技巧整理，主要在說明如何結合 cURL 和 DOM 來解析網頁中的連結：
Scraping Links With PHP
節錄如下：

What You'll Learn

How to use cURL to get the content from a website (URL).
Call PHP DOM functions to parse the HTML so you can extract links.
Use XPath to grab links from specific parts of a page.
Store the scraped links in a MySQL database.
Put it all together into a link scraper.
What else you could use a scraper for.
Legal issues associated with scraping content.

What You Will Need

Basic knowledge of PHP and MySQL.
A web server running PHP 5.
The cURL extension for PHP.
MySQL - if you want to store the links.



		]]>
	</description>
	<content:encoded><![CDATA[
			<p>剛剛看到一篇很有用的 PHP 技巧整理，主要在說明如何結合 cURL 和 DOM 來解析網頁中的連結：</p>
<p><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/" target="_blank">Scraping Links With PHP</a></p>
<p>節錄如下：</p>
<blockquote>
<h3>What You'll Learn</h3>
<ol>
<li><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/#curl_content">How to use cURL</a> to get the content from a website (URL).</li>
<li><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/#php_dom">Call PHP DOM functions</a> to parse the HTML so you can extract links.</li>
<li><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/#xpath_easy">Use XPath to grab links</a> from specific parts of a page.</li>
<li><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/#store_links">Store the scraped links</a> in a MySQL database.</li>
<li><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/#put_together">Put it all together into a link scraper.</a></li>
<li><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/#more_uses">What else you could use a scraper for.</a></li>
<li><a href="http://www.merchantos.com/makebeta/php/scraping-links-with-php/#legal_issues">Legal issues</a> associated with scraping content.</li>
</ol>
<h3>What You Will Need</h3>
<ul>
<li>Basic knowledge of <a href="http://php.net/">PHP</a> and <a href="http://dev.mysql.com/doc/refman/5.0/en/">MySQL</a>.</li>
<li>A web server running PHP 5.</li>
<li>The <a href="http://us.php.net/curl">cURL</a> extension for PHP.</li>
<li>MySQL - if you want to store the links.</li>
</ul>
</blockquote>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3939321.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3939321.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 16 Aug 2007 10:21:29 +0800</pubDate>
</item>
<item>
	<title>[PHP] Namespace in PHP5 Come Back!!</title>
	<description><![CDATA[
			不用等 PHP6 了， Frank Kleine 說 PHP 5.3 就會把 Namespace 帶回來了。原文如下：

Today I saw PHP namespaces in action. Timm Friebe, who backported the namespace patch to PHP5, showed me a namespaced version of the XP-Framework. This was very impressive! We experimented a bit with __autoload() and it was very nice to see that the function is not called on the import but actually when the class is used within the code. Additionally we played around with full and non qualified classnames, with and without the import statement. What I saw looks really promising. Keep your fingers crossed that we will get a PHP5.3 with namespaces!

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>不用等 PHP6 了， <a href="http://www.stubbles.org/archives/22-Namespaces-in-action.html">Frank Kleine</a> 說 PHP 5.3 就會把 Namespace 帶回來了。原文如下：</p>
<blockquote>
<p>Today I saw PHP namespaces in action. Timm Friebe, who <a href="http://www.stubbles.org/exit.php?url_id=182&amp;entry_id=22" onmouseover="window.status='http://news.php.net/php.internals/31143';return true;" onmouseout="window.status='';return true;" title="Announcement of the patch on php-internals.">backported the namespace patch to PHP5</a>, showed me a namespaced version of the XP-Framework. This was very impressive! We experimented a bit with __autoload() and it was very nice to see that the function is not called on the import but actually when the class is used within the code. Additionally we played around with full and non qualified classnames, with and without the import statement. What I saw looks really promising. Keep your fingers crossed that we will get a PHP5.3 with namespaces!</p>
</blockquote>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3719267.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3719267.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 26 Jul 2007 10:03:22 +0800</pubDate>
</item>
<item>
	<title>PHP4 的盡頭</title>
	<description><![CDATA[
			PHP 官方宣佈停止對 PHP4 的支援了，原文如下：

PHP 4 end of life announcement
[13-Jul-2007]
Today it is exactly three years ago since PHP 5 has been released. In those three years it has seen many improvements over PHP 4. PHP 5 is fast, stable &amp; production-ready and as PHP 6 is on the way, PHP 4 will be discontinued.
The PHP development team hereby announces that support for PHP 4 will continue until the end of this year only. After 2007-12-31 there will be no more releases of PHP 4.4. We will continue to make critical security fixes available on a case-by-case basis until 2008-08-08. Please use the rest of this year to make your application suitable to run on PHP 5.
For documentation on migration for PHP 4 to PHP 5, we would like to point you to our migration guide. There is additional information available in the PHP 5.0 to PHP 5.1 and PHP 5.1 to PHP 5.2 migration guides as well.

對某些人來說大概是壞消息，但對我而言卻是很棒的新聞。
PHP 終於醒了...

		]]>
	</description>
	<content:encoded><![CDATA[
			<p><a href="http://www.php.net">PHP 官方</a>宣佈停止對 PHP4 的支援了，原文如下：</p>
<blockquote>
<h3>PHP 4 end of life announcement</h3>
<span class="newsdate">[13-Jul-2007]</span>
<p>Today it is exactly three years ago since PHP 5 has been released. In those three years it has seen many improvements over PHP 4. PHP 5 is fast, stable &amp; production-ready and as PHP 6 is on the way, PHP 4 will be discontinued.</p>
<p>The PHP development team hereby announces that support for PHP 4 will continue until the end of this year only. After 2007-12-31 there will be no more releases of PHP 4.4. We will continue to make critical security fixes available on a case-by-case basis until 2008-08-08. Please use the rest of this year to make your application suitable to run on PHP 5.</p>
<p>For documentation on migration for PHP 4 to PHP 5, we would like to point you to our <a href="/manual/en/migration5.php">migration guide</a>. There is additional information available in the <a href="/manual/en/migration51.php">PHP 5.0 to PHP 5.1</a> and <a href="/manual/en/migration52.php">PHP 5.1 to PHP 5.2</a> migration guides as well.</p>
</blockquote>
<p>對某些人來說大概是壞消息，但對我而言卻是很棒的新聞。</p>
<p>PHP 終於醒了...</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3653075.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3653075.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 13 Jul 2007 18:41:12 +0800</pubDate>
</item>
<item>
	<title>邁向 PHP5</title>
	<description><![CDATA[
			
先前我在「 PHP5 將滿 4 歲」提到許多虛擬主機商不敢升級到 PHP5 ；針對這個問題，前幾天，幾個國外知名開源 PHP 軟體公開推動了 GoPHP5 這個計畫。
以下轉錄對岸網友 lnxcym 提供的翻譯內容：

 [转]多家PHP开源项目联手推动PHP5普及
2007年7月5日消息，一个PHP开发者联盟近日宣布，几家著名的开源PHP项目将在2008年2月5日以后推出的新版软件中，它们将放弃对老版本PHP的支持，以联手推动PHP开发者社区完全向PHP 5迁移。　　包括Symfony、Typo3、phpMyAdmin、Drupal、Propel和Doctrine等在内的开源项目已经都宣布，在2008年2月5日以后发布的新版将要求PHP 5.2版本，以作为对GoPHP5.org支持的一部分，另外，它们还向其他任何PHP项目和应用程序发出了邀请，来共同推动PHP5的普及，不管是开源软件还是专有软件。　　目前大多数基于PHP的Web应用程序即可以运行在PHP4下，又可以运行在PHP5下。PHP 4在2000年发布，并迅速成为主流Web开发语言之一。版本5是在2004年发布，具有很多功能上的改进，但是由于种种原因，被采用的速度却非常慢。　　Drupal的开发者兼GoPHP5.org的创始人之一Larry Garfield表示，“和我交流过的大多数PHP开发者都想使用PHP 5，但是由于许多Web主机只默认提供对PHP 4的支持，因此实际上并没有使用。而Web主机不会升级是因为项目没有升级，而项目之所以不升级是因为Web主机没有升级。这使得许多项目在放弃对PHP4的支持的时候感到为难，因此，我们计划从自身做起，为推动PHP5的普及而努力。”　　通过预先宣布计划在2008年的软件版本中要求PHP 5.2，GoPHP5希望借此来推动Web主机开始升级他们的服务器到更新、更稳定和功能更丰富的PHP版本，并且让它们有充分的时间来完成这个工作。同时，那些使用相关项目的现在版本的用户也不会被冷落。所有相关项目将继续支持现有建立在PHP4上的版本，以保持他们的正常生活秩序，给用户和运营商时间来计划和实施升级。　　phpMyAdmin的项目领导Marc Delisle补充说，“phpMyAdmin项目对加入GoPHP5活动非常热情，我们将GoPHP5看作完善我们产品的新版本的方式，不用不得不投入精力保持其PHP4兼容性，另外还可以改善我们用户的体验。”　　PHP 5为开发者提供了大量的新功能，来帮助开发者更快速的开发现在的Web应用程序，其中包括大大提高的Web服务的XML处理能力，一个被叫做SQLLite的完整SQL数据库，更好的对时区处理，令人印象深刻的完善的安全工具，更强大的面向对象功能，等等。许多PHP项目已经要求使用PHP 5。通过推广PHP 5的安装范围的行动，也将扩大这些项目的市场范围。　　PHP是一个广泛应用的通用脚本语言，尤其适合于Web开发。PHP是当前领先的Web开发语言之一，可以运行在第三方Web服务器上，目前被包括从Yahoo到Facebook在内的众多知名IT网站所选用。    更多信息，请访问以下网站：    http://gophp5.org/    http://www.phpmyadmin.net/home_page/gophp5.php    http://drupal.org/gophp5

我個人也希望能藉由這樣的計畫，推動更多 PHP 開發者朝向 PHP5 前進；尤其目前 Zend Framework 的釋出，也讓我對 PHP5 的未來更加看好。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p class="image"><a href="http://gophp5.org/" target="_blank"><img src="http://gophp5.org/sites/gophp5.org/files/gophp5_logo.png" alt="GoPHP5" border="0" /></a></p>
<p>先前我在「 <a href="http://blog.roodo.com/jaceju/archives/3517185.html" target="_blank">PHP5 將滿 4 歲</a>」提到許多虛擬主機商不敢升級到 PHP5 ；針對這個問題，前幾天，幾個國外知名開源 PHP 軟體公開推動了 <a href="http://gophp5.org/" target="_blank">GoPHP5</a> 這個計畫。</p>
<p>以下轉錄對岸網友 <a href="http://club.phpe.net/index.php?act=Profile&amp;CODE=03&amp;MID=9388">lnxcym</a> 提供的<a href="http://club.phpe.net/index.php?act=ST&amp;f=2&amp;t=15989">翻譯內容</a>：</p>
<blockquote>
<h4> <strong>[转]多家PHP开源项目联手推动PHP5普及</strong></h4>
<p>2007年7月5日消息，一个PHP开发者联盟近日宣布，几家著名的开源PHP项目将在2008年2月5日以后推出的新版软件中，它们将放弃对老版本PHP的支持，以联手推动PHP开发者社区完全向PHP 5迁移。<br /><br />　　包括Symfony、Typo3、phpMyAdmin、Drupal、Propel和Doctrine等在内的开源项目已经都宣布，在2008年2月5日以后发布的新版将要求PHP 5.2版本，以作为对GoPHP5.org支持的一部分，另外，它们还向其他任何PHP项目和应用程序发出了邀请，来共同推动PHP5的普及，不管是开源软件还是专有软件。<br /><br />　　目前大多数基于PHP的Web应用程序即可以运行在PHP4下，又可以运行在PHP5下。PHP 4在2000年发布，并迅速成为主流Web开发语言之一。版本5是在2004年发布，具有很多功能上的改进，但是由于种种原因，被采用的速度却非常慢。<br /><br />　　Drupal的开发者兼GoPHP5.org的创始人之一Larry Garfield表示，“和我交流过的大多数PHP开发者都想使用PHP 5，但是由于许多Web主机只默认提供对PHP 4的支持，因此实际上并没有使用。而Web主机不会升级是因为项目没有升级，而项目之所以不升级是因为Web主机没有升级。这使得许多项目在放弃对PHP4的支持的时候感到为难，因此，我们计划从自身做起，为推动PHP5的普及而努力。”<br /><br />　　通过预先宣布计划在2008年的软件版本中要求PHP 5.2，GoPHP5希望借此来推动Web主机开始升级他们的服务器到更新、更稳定和功能更丰富的PHP版本，并且让它们有充分的时间来完成这个工作。同时，那些使用相关项目的现在版本的用户也不会被冷落。所有相关项目将继续支持现有建立在PHP4上的版本，以保持他们的正常生活秩序，给用户和运营商时间来计划和实施升级。<br /><br />　　phpMyAdmin的项目领导Marc Delisle补充说，“phpMyAdmin项目对加入GoPHP5活动非常热情，我们将GoPHP5看作完善我们产品的新版本的方式，不用不得不投入精力保持其PHP4兼容性，另外还可以改善我们用户的体验。”<br /><br />　　PHP 5为开发者提供了大量的新功能，来帮助开发者更快速的开发现在的Web应用程序，其中包括大大提高的Web服务的XML处理能力，一个被叫做SQLLite的完整SQL数据库，更好的对时区处理，令人印象深刻的完善的安全工具，更强大的面向对象功能，等等。许多PHP项目已经要求使用PHP 5。通过推广PHP 5的安装范围的行动，也将扩大这些项目的市场范围。<br /><br />　　PHP是一个广泛应用的通用脚本语言，尤其适合于Web开发。PHP是当前领先的Web开发语言之一，可以运行在第三方Web服务器上，目前被包括从Yahoo到Facebook在内的众多知名IT网站所选用。<br /><br />    更多信息，请访问以下网站：<br /><br />    <a href="http://gophp5.org/" target="_blank">http://gophp5.org/</a><br />    <a href="http://www.phpmyadmin.net/home_page/gophp5.php" target="_blank">http://www.phpmyadmin.net/home_page/gophp5.php</a><br />    <a href="http://drupal.org/gophp5" target="_blank">http://drupal.org/gophp5</a></p>
</blockquote>
<p>我個人也希望能藉由這樣的計畫，推動更多 PHP 開發者朝向 PHP5 前進；尤其目前 Zend Framework 的釋出，也讓我對 PHP5 的未來更加看好。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3619027.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3619027.html</guid>
	<category> PHP</category>
	<pubDate>Sun, 08 Jul 2007 17:41:09 +0800</pubDate>
</item>
<item>
	<title>Namespaces in PHP6 逆襲！ </title>
	<description><![CDATA[
			原本 PHP5 在 beta 版時有實作 Namespaces 的概念，但是因為某些因素而使得在正式推出時拿掉了。 
昨天 Dmitry Stogov 又把 Namespaces 的想法帶回 PHP 了，整理一下相關的連結：


[PHP-DEV] Simple Namespace Proposal (相關討論)



PHP namespaces


Namespaces - can we keep it  simple?


基本上我個人覺得還不錯，不過工作忙加上資歷不深，沒有什麼高明的見解，所以詳細的討論就留給各位高手們發表了。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>原本 PHP5 在 beta 版時有實作 Namespaces 的概念，但是因為某些因素而使得在正式推出時拿掉了。 </p>
<p>昨天 Dmitry Stogov 又把 Namespaces 的想法帶回 PHP 了，整理一下相關的連結：</p>
<ul>
<li>
<p><a href="http://marc.info/?l=php-dev&amp;m=118355320225178&amp;w=2">[PHP-DEV] Simple Namespace Proposal</a> (<a href="http://marc.info/?t=118355328300005&amp;r=1&amp;w=2">相關討論</a>)
</p>
</li>
<li>
<p><a href="http://www.rooftopsolutions.nl/article/139">PHP namespaces</a></p>
</li>
<li>
<p><a href="http://php100.wordpress.com/2007/07/05/namespaces-can-we-keep-it-simple/" rel="bookmark" title="Permanent Link to Namespaces - can we keep it simple?">Namespaces - can we keep it  simple?</a></p>
</li>
</ul>
<p>基本上我個人覺得還不錯，不過工作忙加上資歷不深，沒有什麼高明的見解，所以詳細的討論就留給各位高手們發表了。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3603131.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3603131.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 06 Jul 2007 10:23:05 +0800</pubDate>
</item>
<item>
	<title>PHPUnit 3.1.0 釋出</title>
	<description><![CDATA[
			這個月 (2007/07) 好像大家都說好了，我所關注的幾個專案都釋出了新版本。剛剛 PHPUnit 也釋出了 3.1.0 版，主要特色如下：


Improvements to Mock Objects include the ability to mock classes and methods that do not exist as  well as mocking static methods. And mocked methods can raise exceptions  now.


PHPUnit's Selenium RC extension no longer uses the Testing_Selenium PEAR package but its own implementation of the Selenium RC client/server protocol. Among other benefits, this allows for the collection of code coverage data for Selenium tests.


PHPUnit can now write test result and code coverage data to a test database. Several ideas for future features depend on this data.


New template methods, PHPUnit_Framework_TestCase::sharedAssertions(), PHPUnit_Framework_TestSuite::setUp(), PHPUnit_Framework_TestSuite::tearDown(), and PHPUnit_Extensions_SeleniumTestCase::defaultAssertions(), ease the development of test cases.


PHPUnit_Framework_TestCase::assertEquals() can now operate on DOMDocument objects.


And lots of smaller improvements all over the place.


沒空翻譯了...請各位朋友自行參考 Changelog 。
時間越來越少，要學的東西越來越多....Orz 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>這個月 (2007/07) 好像大家都說好了，我所關注的幾個專案都釋出了新版本。剛剛 <a href="http://www.phpunit.de/">PHPUnit</a> 也<a href="http://sebastian-bergmann.de/archives/682-PHPUnit-3.1.0.html">釋出了 3.1.0 版</a>，主要特色如下：</p>
<ul>
<li>
<p>Improvements to <a href="http://www.phpunit.de/pocket_guide/3.1/en/mock-objects.html">Mock Objects</a> include the ability to mock classes and methods that do not exist as  well as mocking static methods. And mocked methods can raise exceptions  now.</p>
</li>
<li>
<p><a href="http://www.phpunit.de/pocket_guide/3.1/en/selenium.html">PHPUnit's Selenium RC extension</a> no longer uses the Testing_Selenium PEAR package but its own implementation of the <a href="http://www.openqa.org/selenium-rc">Selenium RC</a> client/server protocol. Among other benefits, this allows for the collection of code coverage data for Selenium tests.</p>
</li>
<li>
<p>PHPUnit can now write test result and code coverage data to a <a href="http://www.phpunit.de/wiki/TestDatabase">test database</a>. Several <a href="http://www.phpunit.de/wiki/Ideas">ideas for future features</a> depend on this data.</p>
</li>
<li>
<p>New template methods, PHPUnit_Framework_TestCase::sharedAssertions(), PHPUnit_Framework_TestSuite::setUp(), PHPUnit_Framework_TestSuite::tearDown(), and PHPUnit_Extensions_SeleniumTestCase::defaultAssertions(), ease the development of test cases.</p>
</li>
<li>
<p>PHPUnit_Framework_TestCase::assertEquals() can now operate on DOMDocument objects.</p>
</li>
<li>
<p>And lots of smaller improvements all over the place.</p>
</li>
</ul>
<p>沒空翻譯了...請各位朋友自行參考 <a href="http://www.phpunit.de/wiki/ChangeLog#PHPUnit3.1.002-Jul-2007">Changelog</a> 。</p>
<p>時間越來越少，要學的東西越來越多....Orz </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3567377.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3567377.html</guid>
	<category> PHP</category>
	<pubDate>Mon, 02 Jul 2007 21:02:18 +0800</pubDate>
</item>
<item>
	<title>整理最近 PHP5 的相關文章</title>
	<description><![CDATA[
			因為最近正在利用 Zend Framework 開發一個新專案，目標是減少開發的時間，也因此重新試著瞭解 PHP5 的一些特性。沒想到我對 PHP5 粗淺的見解，引出了兩位高手的熱烈討論及迴響，趁著工作閒暇整理一下：
阿土伯 (Racklin)

Iterators in PHP5
 Observer Pattern in PHP5
Get class name in static method ( Java and PHP )

石頭成 (Rocksaying) 

為什麼還不升級PHP5
Use ArrayObject and ArrayIterator to Overload Operators of Array
Stack - Example for Operators of Array Overload
PHP5 的個體導向能力問題 - magic methods 和 interface

註：我還真的是拋磚引玉呢。 XD 
如果對 PHP5 有興趣的朋友，以上文章務必要參考看看。
至於我個人所抱持的簡陋想法是： PHP 會走出屬於自己的一條路，它一定會隨著時間而進化的。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>因為最近正在利用 <a href="http://framework.zend.com">Zend Framework</a> 開發一個新專案，目標是減少開發的時間，也因此重新試著瞭解 PHP5 的一些特性。沒想到我對 PHP5 粗淺的見解，引出了兩位高手的熱烈討論及迴響，趁著工作閒暇整理一下：</p>
<h2><a href="http://racklin.blogspot.com/">阿土伯 (Racklin)</a></h2>
<ul>
<li><a href="http://racklin.blogspot.com/2007/06/iterators-in-php5.html">Iterators in PHP5</a></li>
<li> <a href="http://racklin.blogspot.com/2007/06/observer-pattern-in-php5.html">Observer Pattern in PHP5</a></li>
<li><a href="http://racklin.blogspot.com/search/label/PHP">Get class name in static method ( Java and PHP )</a></li>
</ul>
<h2><a href="http://blog.roodo.com/rocksaying/">石頭成 (Rocksaying)</a> </h2>
<ul>
<li><a href="http://blog.roodo.com/rocksaying/archives/3526951.html">為什麼還不升級PHP5</a></li>
<li><a href="http://blog.roodo.com/rocksaying/archives/3532653.html">Use ArrayObject and ArrayIterator to Overload Operators of Array</a></li>
<li><a href="http://blog.roodo.com/rocksaying/archives/3542135.html">Stack - Example for Operators of Array Overload</a></li>
<li><a href="http://blog.roodo.com/rocksaying/archives/3547207.html">PHP5 的個體導向能力問題 - magic methods 和 interface</a></li>
</ul>
<p class="note">註：我還真的是<a href="http://blog.roodo.com/jaceju/archives/3517185.html#comment-11054673">拋磚引玉</a>呢。 XD </p>
<p>如果對 PHP5 有興趣的朋友，以上文章務必要參考看看。</p>
<p>至於我個人所抱持的簡陋想法是： PHP 會走出屬於自己的一條路，它一定會隨著時間而進化的。 </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3549457.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3549457.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 29 Jun 2007 00:19:31 +0800</pubDate>
</item>
<item>
	<title>PHP5 將滿 4 歲</title>
	<description><![CDATA[
			PHP5 從 beta 版釋出，到今年的 6 月 29 日將滿 4 週年，也因此 Davey Shafik 感嘆大家為什麼還在使用 PHP4 ？
為什麼呢？就台灣目前的環境而言，我想到的原因有以下幾個：


很多舊的應用程式對 PHP5 這個執行環境感冒。 


承上一點，虛擬主機商多數不敢升級到 PHP5 。


很多 PHPer 不瞭解 PHP4 和 PHP5 的差異。


承上一點，台灣沒有作者敢寫 PHP5 的進階應用書籍。 (嗯...這有點用到激將法...) 


事實上，台灣不像歐洲對 PHP 有那麼多的愛好者，多數人學它只是因為簡單而且容易找到案子接。然而也是因為 PHP4 過於簡單，導致很多人常常不會深入去瞭解 PHP 這個 Script 語言，更別提 PHP5 所加入的物件導向特性對他們來說像是怪獸一樣可怕了。
老實說，我自己學習 PHP5 的時間也不過短短不到一年；這期間我督促自己儘可能地熟悉物件導向，並深入去摸索 PHP5 的進階用法。可是我自認自己還是有很多地方不甚瞭解，希望未來在眾多高手的指導下，能讓我自己對 PHP 這個工具有進一步的認識。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>PHP5 從 beta 版釋出，到今年的 6 月 29 日將滿 4 週年，也因此 <a href="http://pixelated-dreams.com/">Davey Shafik</a> <a href="http://pixelated-dreams.com/archives/305-Do-you-know-what-June-29th-is.html">感嘆</a>大家為什麼還在使用 PHP4 ？</p>
<p>為什麼呢？就台灣目前的環境而言，我想到的原因有以下幾個：</p>
<ul>
<li>
<p>很多舊的應用程式對 PHP5 這個執行環境感冒。 </p>
</li>
<li>
<p>承上一點，虛擬主機商多數不敢升級到 PHP5 。</p>
</li>
<li>
<p>很多 PHPer 不瞭解 PHP4 和 PHP5 的差異。</p>
</li>
<li>
<p>承上一點，台灣沒有作者敢寫 PHP5 的進階應用書籍。 (嗯...這有點用到激將法...) </p>
</li>
</ul>
<p>事實上，台灣不像歐洲對 PHP 有那麼多的愛好者，多數人學它只是因為簡單而且容易找到案子接。然而也是因為 PHP4 過於簡單，導致很多人常常不會深入去瞭解 PHP 這個 Script 語言，更別提 PHP5 所加入的物件導向特性對他們來說像是怪獸一樣可怕了。</p>
<p>老實說，我自己學習 PHP5 的時間也不過短短不到一年；這期間我督促自己儘可能地熟悉物件導向，並深入去摸索 PHP5 的進階用法。可是我自認自己還是有很多地方不甚瞭解，希望未來在眾多高手的指導下，能讓我自己對 PHP 這個工具有進一步的認識。 </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3517185.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3517185.html</guid>
	<category> PHP</category>
	<pubDate>Sat, 23 Jun 2007 14:10:36 +0800</pubDate>
</item>
<item>
	<title>PHP 為什麼快？</title>
	<description><![CDATA[
			今天看到鳥毅老大提了一個問題：PHP 為什麼快呢？本來想回應在他的 Blog 上，不過寫一寫又太長了，就貼在自己家吧。
這個問題我想有一部份原因是因為大多數 PHP 函式是直接包裝 C 函式的關係吧？不然光只有 PHP Script 的話 (看看現在的框架應該可以略知一二) ，速度其實也就還好。所以很多時候會聽到一些 PHP 高手告誡我們：如果有現成的 PHP 函式能用的話就用，千萬不要自己寫一個。
另外 PHP 簡單我想也真的是一個重點，鳥毅老大是這麼說的：

Java Servlet或是ASP.Net的overhead都太重，因此對於簡單的需求時會像背著厚重殼的烏龜，PHP就像輕穎的兔子；這也是約耳喜歡ASP的原因吧？若只要寫個九九乘法表還需要寫一堆class、呼叫笨重的VM，實在不是聰明的做法。因此只需要在shell下執行的小程式，我也試著用不熟悉的駱駝文寫些簡單的script；只有在需要連結資料庫或做大量運算時才用Java。雖然qing老大強調OO帶來的overhead已經很小，可是我還是覺得有個肥VM的東西就是很慢呀... eg. Java v.s. VB6

例如一個 echo 指令，從解譯到把結果交給 Web Server ，其過程所要處理的東西遠比 ASP.NET 或是 Java Solution 來的少 (它們都需要類別或物件來處理) 。就算是已經編譯好的 opcode ，也是得透過 VM 來執行。而 PHP 有時候就直接利用 C 函式產生結果，然後丟給 Web Server 或 CLI 等 console ；因此少了一層包裝，其效能就好很多。 
換句話說： PHP 作弊。
 PHP 原本就是靠 Web Server Script 起家的，能儘量利用現有的東西來組合是它的特色也是優點。而現在 PHP5 及未來的版本為了兼顧維護與效能，就漸漸地靠攏 Java ，將物件導向特性包含進來；但是這只是讓 PHP5 語法在表面上看起來像是物件導向語言，但它骨子裡仍然不是。
註：昨天也和 Mark 討論到 (他希望我不要再叫他老大 XD ) ， 我們還是希望 PHP 不要完全變成 Java (|||orz 被騙得很慘)，而是要像 JavaScript (ECMAScript) ，這樣能結合靜態語言及動態語言的長處 (也許有人抱持和我不一樣的看法，歡迎指教) 。 
而提到了維護，傳統 PHP 寫法難以維護也是真的。因為沒有像 RoR 這種統一的架構，變成每個 PHPer 有自己一套開發風格；就算一律採用 Smarty 及 ADOdb 或其他類別庫來開發，每個 PHPer 在架構上的規劃還是大相逕庭。而且雖然現在 PHP 也有框架了，不過在選擇上也是令人眼花撩亂，更別提每個框架的開發者都認為自己的框架才是經過千錘百煉的。
註：大概很少有人會拿我書裡面的 Smarty 架構做專案吧？我個人強烈建議各位要自己修改，不要照抄 XD 。 
PHP 有它的優點，當然也有缺點；我想任何語言也是一樣的。其實我也不喜歡爭論孰優孰劣，只要這套語言仍是我所熟稔且能應用自如的話，那麼它就是我目前最佳的選擇了。 
以上是我個人的看法與經驗，不一定正確，希望各位先進能不吝指教。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>今天看到<a href="http://blog.tenyi.com/">鳥毅</a>老大提了一個問題：<a href="http://blog.tenyi.com/2007/06/php.html">PHP 為什麼快呢？</a>本來想回應在他的 Blog 上，不過寫一寫又太長了，就貼在自己家吧。</p>
<p>這個問題我想有一部份原因是因為大多數 PHP 函式是直接包裝 C 函式的關係吧？不然光只有 PHP Script 的話 (看看現在的框架應該可以略知一二) ，速度其實也就還好。所以很多時候會聽到一些 PHP 高手告誡我們：如果有現成的 PHP 函式能用的話就用，千萬不要自己寫一個。</p>
<p>另外 PHP 簡單我想也真的是一個重點，鳥毅老大是這麼說的：</p>
<blockquote>
<p>Java Servlet或是ASP.Net的overhead都太重，因此對於簡單的需求時會像背著厚重殼的烏龜，PHP就像輕穎的兔子；這也是約耳喜歡ASP的原因吧？若只要寫個九九乘法表還需要寫一堆class、呼叫笨重的VM，實在不是聰明的做法。因此只需要在shell下執行的小程式，我也試著用不熟悉的駱駝文寫些簡單的script；只有在需要連結資料庫或做大量運算時才用Java。雖然qing老大強調OO帶來的overhead已經很小，可是我還是覺得有個肥VM的東西就是很慢呀... eg. Java v.s. VB6</p>
</blockquote>
<p>例如一個 echo 指令，從解譯到把結果交給 Web Server ，其過程所要處理的東西遠比 ASP.NET 或是 Java Solution 來的少 (它們都需要類別或物件來處理) 。就算是已經編譯好的 opcode ，也是得透過 VM 來執行。而 PHP 有時候就直接利用 C 函式產生結果，然後丟給 Web Server 或 CLI 等 console ；因此少了一層包裝，其效能就好很多。 </p>
<p>換句話說： <strong>PHP 作弊</strong>。</p>
<p> PHP 原本就是靠 Web Server Script 起家的，能儘量利用現有的東西來組合是它的特色也是優點。而現在 PHP5 及未來的版本為了兼顧維護與效能，就漸漸地靠攏 Java ，將物件導向特性包含進來；但是這只是讓 PHP5 語法在表面上看起來像是物件導向語言，但它骨子裡仍然不是。</p>
<p class="note">註：昨天也和 <a href="http://blog.markplace.net/">Mark</a> 討論到 (他希望我不要再叫他老大 XD ) ， 我們還是希望 PHP 不要<a href="http://mk.netgenes.org/archives/546/">完全變成 Java</a> (|||orz 被騙得很慘)，而是要像 JavaScript (<a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript</a>) ，這樣能結合靜態語言及動態語言的長處 (也許有人抱持和我不一樣的看法，歡迎指教) 。 </p>
<p>而提到了維護，傳統 PHP 寫法難以維護也是真的。因為沒有像 <a href="http://www.rubyonrails.org/">RoR</a> 這種統一的架構，變成每個 PHPer 有自己一套開發風格；就算一律採用 <a href="http://smarty.php.net">Smarty</a> 及 <a href="http://adodb.sourceforge.net/">ADOdb</a> 或其他類別庫來開發，每個 PHPer 在架構上的規劃還是大相逕庭。而且雖然現在 PHP 也有框架了，不過在選擇上也是令人眼花撩亂，更別提每個框架的開發者都認為自己的框架才是經過千錘百煉的。</p>
<p class="note">註：大概很少有人會拿我書裡面的 Smarty 架構做專案吧？我個人強烈建議各位要自己修改，不要照抄 XD 。 </p>
<p>PHP 有它的優點，當然也有缺點；我想任何語言也是一樣的。其實我也不喜歡爭論孰優孰劣，只要這套語言仍是我所熟稔且能應用自如的話，那麼它就是我目前最佳的選擇了。 </p>
<p>以上是我個人的看法與經驗，不一定正確，希望各位先進能不吝指教。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3510483.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3510483.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 22 Jun 2007 11:31:07 +0800</pubDate>
</item>
<item>
	<title>PHP 的 Application 層</title>
	<description><![CDATA[
			前陣子才在和 Mark 老大談論到 PHP 的 Application 層，今天就看到有人做出類似的東西了。
請參考： Application Server in PHP? well… Yes!
文章中主要是利用 SCGI 這個協定實作了一個 SCGI_Application 類別讓我們的應用程式繼承，這樣一來這個 Application 就會像是一個伺服器一樣，使用 9999 (預設值) 這個 Port 來回應 Web 伺服器所傳來的要求。這裡有範例可以參考，有興趣的朋友不妨試試。 
什麼是 Application 層呢？我們都知道 PHP 在處理每一次的用戶要求時，都會重頭執行一次 Script ，然後初始化每個物件 (像是資料庫、樣版引擎或是 Model 物件等等) 。當然在流量小的網站，這樣的方式並沒有什麼不妥；可是一旦流量變大時，每一次的初始化都會浪費掉些許的時間，而累積起來後就會造成伺服器的負擔。這種現象是因為 HTTP 協定的無狀態特性使然，對所有 Web 伺服端技術而言都是一樣的。 
所以如果能在 Web 伺服器的上面加上一個 Application 伺服器，就能夠利用這個伺服器所產生的抽象 Application 層來保存住這些常用物件。也就是說在 Application 層裡，我們會把共用物件常駐在記憶體裡，避免物件初始化所帶來的效能問題。例如在 Java Tomcat 或 Resin 裡，我們能把 Java Bean 持續地放在記憶體裡保持住它的狀態；如此一來在每一個要求裡所看到的 Bean 物件其實就是同一個。
然而目前 PHP 因為沒有類似 Tomcat 這種 Application Server 來協助儲存狀態，所以在效能上就會有所折扣；也因此 PHP 才會有 APC 或是 eAccelerator 這樣的加速器。
註：雖然 Resin 目前也支援 PHP ，不過據 Mark 老大的說法，在 Resin 使用 PHP 就必須採用 JDBC 來連接資料庫。這樣的話，實用價值似乎不大。 它在資料庫存取時會利用 JDBC 來模擬，使 PHP 原有的存取方式可以不用更動。
除了加速器外，在 PHP 中我們倒是有另一種保持物件的方式，那就是快取。一般來說，我們會利用序列化 (serialize) 把物件狀態存在檔案或記憶體裡，比較常見的方式就是利用 memcached 。不過就算使用了快取，我們其實還是得在 PHP 程式裡初始化相關的快取物件才行，這又回到了前面所談到的問題。
註：當然加速器也是另一種形態的快取，不過對儲存物件狀態的功效不大。
另外在 MVC 框架中，會嚴重影響效能的物件就是 Controller 了。像 Front Controller 就必須判斷使用者的要求，進一步將這些要求分派 (dispatch) 到特定的 Action Controller 裡，而每一次的分派其實就會佔用掉大部份的執行時間。所以如果 Controller 能夠編譯並結合到 Application 伺服器的話，那麼程式執行的效率就會進一步的提升。
當然我本身是希望 PHP 也能提供這樣的機制，或是將 Zend Framework 變成一個 PHP 的 extension 。嗯，也許我是痴人說夢，但我衷心希望有這一天的來臨。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>前陣子才在和 <a href="http://blog.markplace.net/">Mark</a> 老大談論到 PHP 的 Application 層，今天就看到有人做出類似的東西了。</p>
<p>請參考： <a href="http://blog.milkfarmsoft.com/?p=51">Application Server in PHP? well… Yes!</a></p>
<p>文章中主要是利用 <a href="http://python.ca/scgi/">SCGI</a> 這個協定實作了一個 SCGI_Application 類別讓我們的應用程式繼承，這樣一來這個 Application 就會像是一個伺服器一樣，使用 9999 (預設值) 這個 Port 來回應 Web 伺服器所傳來的要求。這裡有<a href="http://appserver-in-php.googlecode.com/svn/trunk/examples/scgi/">範例</a>可以參考，有興趣的朋友不妨試試。 </p>
<p>什麼是 Application 層呢？我們都知道 PHP 在處理每一次的用戶要求時，都會重頭執行一次 Script ，然後初始化每個物件 (像是資料庫、樣版引擎或是 Model 物件等等) 。當然在流量小的網站，這樣的方式並沒有什麼不妥；可是一旦流量變大時，每一次的初始化都會浪費掉些許的時間，而累積起來後就會造成伺服器的負擔。這種現象是因為 HTTP 協定的無狀態特性使然，對所有 Web 伺服端技術而言都是一樣的。 </p>
<p>所以如果能在 Web 伺服器的上面加上一個 Application 伺服器，就能夠利用這個伺服器所產生的抽象 Application 層來保存住這些常用物件。也就是說在 Application 層裡，我們會把共用物件常駐在記憶體裡，避免物件初始化所帶來的效能問題。例如在 Java Tomcat 或 <a href="http://www.caucho.com/resin-3.0/">Resin</a> 裡，我們能把 Java Bean 持續地放在記憶體裡保持住它的狀態；如此一來在每一個要求裡所看到的 Bean 物件其實就是同一個。</p>
<p>然而目前 PHP 因為沒有類似 <a href="http://tomcat.apache.org/">Tomcat</a> 這種 Application Server 來協助儲存狀態，所以在效能上就會有所折扣；也因此 PHP 才會有 <a href="http://pecl.php.net/package/APC">APC</a> 或是 <a href="http://eaccelerator.net/">eAccelerator</a> 這樣的加速器。</p>
<p class="note">註：<del>雖然</del> Resin 目前也<a href="http://www.caucho.com/resin-3.1/doc/quercus-resin-module.xtp">支援 PHP</a> ，<del>不過據 Mark 老大的說法，在 Resin 使用 PHP 就必須採用 JDBC 來連接資料庫。這樣的話，實用價值似乎不大。</del> 它在資料庫存取時會利用 JDBC 來模擬，使 PHP 原有的存取方式可以不用更動。</p>
<p>除了加速器外，在 PHP 中我們倒是有另一種保持物件的方式，那就是快取。一般來說，我們會利用序列化 (<a href="http://www.php.net/manual/en/function.serialize.php">serialize</a>) 把物件狀態存在檔案或記憶體裡，比較常見的方式就是利用 <a href="http://danga.com/memcached/">memcached</a> 。不過就算使用了快取，我們其實還是得在 PHP 程式裡初始化相關的快取物件才行，這又回到了前面所談到的問題。</p>
<p class="note">註：當然加速器也是另一種形態的快取，不過對儲存物件狀態的功效不大。</p>
<p>另外在 MVC 框架中，會嚴重影響效能的物件就是 Controller 了。像 Front Controller 就必須判斷使用者的要求，進一步將這些要求分派 (dispatch) 到特定的 Action Controller 裡，而每一次的分派其實就會佔用掉大部份的執行時間。所以如果 Controller 能夠編譯並結合到 Application 伺服器的話，那麼程式執行的效率就會進一步的提升。</p>
<p>當然我本身是希望 PHP 也能提供這樣的機制，或是將 Zend Framework 變成一個 PHP 的 extension 。嗯，也許我是痴人說夢，但我衷心希望有這一天的來臨。 </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3496701.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3496701.html</guid>
	<category> PHP</category>
	<pubDate>Tue, 19 Jun 2007 23:00:05 +0800</pubDate>
</item>
<item>
	<title>Xinc - 整合 PHP 測試、發佈的工具</title>
	<description><![CDATA[
			Xinc 主要是整合 Subversion 、 PHPUnit 、 Phing 這三個工具，成為一個 PHP5  的Continuous Integration System 。簡單來說應該有點像是 Java 的 Ant ，可以協助我們在散佈套件時，進行自動化的安裝與測試。(應該吧？) 
不過我對類似的工具不甚瞭解 (畢竟我很少開發 Java 的案子) ，還望有經驗的先進能不吝指導。



		]]>
	</description>
	<content:encoded><![CDATA[
			<p><a href="http://xinc.entrypoint.biz/">Xinc</a> 主要是整合 Subversion 、 PHPUnit 、 Phing 這三個工具，成為一個 PHP5  的<a href="http://www.martinfowler.com/articles/continuousIntegration.html">Continuous Integration System</a> 。簡單來說應該有點像是 Java 的 Ant ，可以協助我們在散佈套件時，進行自動化的安裝與測試。(應該吧？) </p>
<p>不過我對類似的工具不甚瞭解 (畢竟我很少開發 Java 的案子) ，還望有經驗的先進能不吝指導。</p>



		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3452613.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3452613.html</guid>
	<category> PHP</category>
	<pubDate>Mon, 11 Jun 2007 23:05:22 +0800</pubDate>
</item>
<item>
	<title>PHPUnit 教學研討會 (國外)</title>
	<description><![CDATA[
			PHPUnit Tutorial @ ZendCon 2007
Sebastian Bergmann 老大親自授課...一整個就是好想去...|||orz
		]]>
	</description>
	<content:encoded><![CDATA[
			<p><a href="http://www.zendcon.com/schedule_tutorials.php">PHPUnit Tutorial @ ZendCon 2007</a></p>
<p><a href="http://sebastian-bergmann.de/">Sebastian Bergmann</a> 老大親自授課...一整個就是好想去...|||orz</p>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3344359.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3344359.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 25 May 2007 10:13:52 +0800</pubDate>
</item>
<item>
	<title>Anonymous functions in PHP</title>
	<description><![CDATA[
			國外最近有一些 PHP 的技術研討會，其中比較有趣的一項是：匿名函式 (Anonymous functions) 。
範例如下：
$data = array("zoo", "orange", "car", "lemon", "apple");
usort($data, function($a, $b) { return strcmp($a, $b); });
var_dump($data); # data is sorted alphabetically
沒錯，看起來就像是 JavaScript 的 function literal 。
這樣一來我們可以不需要再使用 create_function ，也不必撰寫有一堆跳脫字元的醜陋函式字串，而能更直覺地寫出我們所需要的函式。文章裡還有其他關於匿名函式的範例，有興趣的朋友可以自行參考。
話雖如此，到底哪個版本才會有這麼好用的東西出來呀？我的 mixin 類別正在找尋歸屬說。 
註：不過裡面 Jim Wilson 也提到了 (就是 Smarty 網站上常看到的  boots 本人) ，匿名函式和 closure (石頭成老大譯：封絕) 是完全不一樣的東西，而 PHP 是不需要 closure 的。可是為什麼我看感覺是一樣的？唉...大概是我等級還不夠，看不出什麼所以然吧？

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>國外最近有一些 PHP 的<a href="http://www.php.net/conferences/">技術研討會</a>，其中比較有趣的一項是：<a href="http://devzone.zend.com/node/view/id/2013">匿名函式</a> (Anonymous functions) 。</p>
<p>範例如下：</p>
<pre><code><span style="color: rgb(0, 0, 0);"><span style="color: rgb(0, 0, 187);">$data </span><span style="color: rgb(0, 119, 0);">= array(</span><span style="color: rgb(221, 0, 0);">"zoo"</span><span style="color: rgb(0, 119, 0);">, </span><span style="color: rgb(221, 0, 0);">"orange"</span><span style="color: rgb(0, 119, 0);">, </span><span style="color: rgb(221, 0, 0);">"car"</span><span style="color: rgb(0, 119, 0);">, </span><span style="color: rgb(221, 0, 0);">"lemon"</span><span style="color: rgb(0, 119, 0);">, </span><span style="color: rgb(221, 0, 0);">"apple"</span><span style="color: rgb(0, 119, 0);">);
</span><span style="color: rgb(0, 0, 187);"><a href="/manual/view/page/function.usort.html">usort</a></span><span style="color: rgb(0, 119, 0);">(</span><span style="color: rgb(0, 0, 187);">$data</span><span style="color: rgb(0, 119, 0);">, function(</span><span style="color: rgb(0, 0, 187);">$a</span><span style="color: rgb(0, 119, 0);">, </span><span style="color: rgb(0, 0, 187);">$b</span><span style="color: rgb(0, 119, 0);">) { return </span><span style="color: rgb(0, 0, 187);"><a href="/manual/view/page/function.strcmp.html">strcmp</a></span><span style="color: rgb(0, 119, 0);">(</span><span style="color: rgb(0, 0, 187);">$a</span><span style="color: rgb(0, 119, 0);">, </span><span style="color: rgb(0, 0, 187);">$b</span><span style="color: rgb(0, 119, 0);">); });
</span><span style="color: rgb(0, 0, 187);"><a href="/manual/view/page/function.var-dump.html">var_dump</a></span><span style="color: rgb(0, 119, 0);">(</span><span style="color: rgb(0, 0, 187);">$data</span><span style="color: rgb(0, 119, 0);">); </span><span style="color: rgb(255, 128, 0);"># data is sorted alphabetically</span></span></code></pre>
<p>沒錯，看起來就像是 JavaScript 的 function literal 。</p>
<p>這樣一來我們可以不需要再使用 <a href="http://www.php.net/en/create_function">create_function</a> ，也不必撰寫有一堆跳脫字元的醜陋函式字串，而能更直覺地寫出我們所需要的函式。文章裡還有其他關於匿名函式的範例，有興趣的朋友可以自行參考。</p>
<p>話雖如此，到底哪個版本才會有這麼好用的東西出來呀？我的 mixin 類別正在找尋歸屬說。 </p>
<p class="note">註：不過裡面 Jim Wilson 也提到了 (就是 Smarty 網站上常看到的  boots 本人) ，匿名函式和 <a href="http://www.javaworld.com.tw/roller/page/ingramchen?entry=2007_1_1_WhyAddClosureInJava7">closure</a> (<a href="http://blog.roodo.com/rocksaying/">石頭成</a>老大譯：<a href="http://blog.roodo.com/rocksaying/archives/3088893.html">封絕</a>) 是完全不一樣的東西，而 PHP 是不需要 closure 的。可是為什麼我看感覺是一樣的？唉...大概是我等級還不夠，看不出什麼所以然吧？</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/3274481.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/3274481.html</guid>
	<category> PHP</category>
	<pubDate>Sat, 19 May 2007 11:18:39 +0800</pubDate>
</item>
<item>
	<title>我也來實作 PHP mix-in 的概念 - Part 3</title>
	<description><![CDATA[
			說明
石頭成老大把他心目中的 mix-in 目標做出來了，他主要的實作有以下兩個重點：

物件實體生成後彼此做 mix-in 是不相干的。
類別方法在動態委派後要能遵守繼承原則，也就是說子承父、父不承子。

另外他也提到要儲存方法是一件困難的事情，因為 PHP 有三種函式的呼叫方法：一般函數、類別靜態方法、實例方法。而我在 Part 2 裡的概念實作則是用 callback 虛擬型態來儲存，不過卻忘了把一般函式給放進去。
不過 Part 2 的實作已經實現了第一個目標，所以在這次 Part 3 的實作裡，我除了決定把一般函式也納入 mix-in 的實作裡，而且還要達成石頭成老大說的第二個目標。
另外我自己也加入了以下實作重點：

所有動作都要在 Prototype 類別裡處理掉，不能夠讓子類別除了自己的工作外，還得實作不必要的部份。 (石頭成老大抱歉啦~我是覺得 $methods 不應該在子類別再次定義。)
Prototype&nbsp; 所延伸的子類別，不能覆蓋 Prototype 類別裡的任何方法，以避免功能出錯。
使用的方法要夠簡單，儘量不要讓使用者感到困惑。

經過一番努力，我終於試出來了；先來看看成果，後面我才來一一分析。

		]]>
	</description>
	<content:encoded><![CDATA[
			<h2>說明</h2>
<p>石頭成老大把他心目中的 mix-in <a href="http://blog.roodo.com/rocksaying/archives/2884871.html" title="目標">目標</a>做出來了，他主要的實作有以下兩個重點：</p>
<ol>
<li>物件實體生成後彼此做 mix-in 是不相干的。</li>
<li>類別方法在動態委派後要能遵守繼承原則，也就是說子承父、父不承子。</li>
</ol>
<p>另外他也提到要儲存方法是一件困難的事情，因為 PHP 有三種函式的呼叫方法：一般函數、類別靜態方法、實例方法。而我在 <a href="http://blog.roodo.com/jaceju/archives/2853761.html">Part 2</a> 裡的概念實作則是用 <a href="http://blog.roodo.com/jaceju/archives/409709.html" title="callback">callback</a> 虛擬型態來儲存，不過<a href="http://blog.roodo.com/jaceju/archives/2853761.html" title="前一版"></a>卻忘了把一般函式給放進去。</p>
<p>不過 Part 2 的實作已經實現了第一個目標，所以在這次 Part 3 的實作裡，我除了決定把一般函式也納入 mix-in 的實作裡，而且還要達成石頭成老大說的第二個目標。</p>
<p>另外我自己也加入了以下實作重點：</p>
<ol>
<li>所有動作都要在 Prototype 類別裡處理掉，不能夠讓子類別除了自己的工作外，還得實作不必要的部份。 (石頭成老大抱歉啦~我是覺得 <span><span class="vars">$methods</span> <span>不應該在子類別再次定義。)<br /></span></span></li>
<li><span><span>Prototype&nbsp; 所延伸的子類別，不能覆蓋 Prototype 類別裡的任何方法，以避免功能出錯。</span></span></li>
<li><span>使用的方法要夠簡單，儘量不要讓使用者感到困惑。</span></li>
</ol>
<p>經過一番努力，我終於試出來了；先來看看成果，後面我才來一一分析。</p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/2915575.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2915575.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2915575.html</guid>
	<category> PHP</category>
	<pubDate>Tue, 27 Mar 2007 00:19:15 +0800</pubDate>
</item>
<item>
	<title>我也來實作 PHP mix-in 的概念 - Part 2</title>
	<description><![CDATA[
			石頭成老大說他要為他的 mix-in 實作 part 2 ，我也想到了一些好玩的東西。記得很久之前我寫過一篇「 PHP 的 callback 虛擬型態」，這次就把它用在這裡。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p><a href="http://blog.roodo.com/rocksaying">石頭成</a>老大說他要為他的 <a href="http://blog.roodo.com/rocksaying/archives/2817003.html">mix-in</a> 實作 part 2 ，我也想到了一些好玩的東西。記得很久之前我寫過一篇「 <a href="http://blog.roodo.com/jaceju/archives/409709.html">PHP 的 callback 虛擬型態</a>」，這次就把它用在這裡。</p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/2853761.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2853761.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2853761.html</guid>
	<category> PHP</category>
	<pubDate>Wed, 14 Mar 2007 22:40:31 +0800</pubDate>
</item>
<item>
	<title>我也來實作 PHP mix-in 的概念</title>
	<description><![CDATA[
			之前提過一篇 Prototype-based programming in PHP ，後來在石頭閒語那裡也看到 PHP 實踐 mix-in 概念之可行性，我自己也手癢寫了一個。不過我是把 function 當成是一個 MethodObject ，有點 delegate 味道。然而大部份限制就像石頭成所說的，所以我也不多提了。還是等 PHP7 的規格出來，看它會不會支援 closure 好了  (要跟隨 Java 7 嗎？ XD) 。
註： PHP 6 可能會實現的東西請參考 Prepare for PHP 6 。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>之前提過一篇 <a href="http://personal.schmalls.com/2006/11/06/prototype-based-programming-in-php/">Prototype-based programming in PHP</a> ，後來在<a href="http://blog.roodo.com/rocksaying">石頭閒語</a>那裡也看到 <a href="http://blog.roodo.com/rocksaying/archives/2817003.html">PHP 實踐 mix-in 概念之可行性</a>，我自己也手癢寫了一個。不過我是把 function 當成是一個 MethodObject ，有點 delegate 味道。然而大部份限制就像石頭成所說的，所以我也不多提了。還是等 PHP7 的規格出來，看它會不會<a href="http://javaworld.com.tw/roller/page/ingramchen?entry=2007_1_1_WhyAddClosureInJava7">支援 closure</a> 好了  (要跟隨 Java 7 嗎？ XD) 。</p>
<p class="note">註： PHP 6 可能會實現的東西請參考 <a href="http://www.corephp.co.uk/archives/19-Prepare-for-PHP-6.html">Prepare for PHP 6</a> 。 </p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/2832709.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2832709.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2832709.html</guid>
	<category> PHP</category>
	<pubDate>Sat, 10 Mar 2007 10:20:59 +0800</pubDate>
</item>
<item>
	<title>Zend PHP5 認證自我測試</title>
	<description><![CDATA[
			在 Zend PHP5 Certification self-test 這篇文章中，作者通過了官方的 Self-Test  8 道題目的測試，大家有興趣的話可以試試看。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>在 <a href="http://blog.agoraproduction.com/index.php?/archives/23-Zend-PHP5-Certification-self-test.html">Zend PHP5 Certification self-test</a> 這篇文章中，作者通過了官方的 <a href="http://www.zend.com/store/education/certification/self-test.php">Self-Test</a>  8 道題目的測試，大家有興趣的話可以試試看。 </p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/2832587.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2832587.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2832587.html</guid>
	<category> PHP</category>
	<pubDate>Sat, 10 Mar 2007 08:18:10 +0800</pubDate>
</item>
<item>
	<title>PHP 官方參考手冊更新</title>
	<description><![CDATA[
			PHP 官方參考手冊為了因應開發的潮流，作了一些改變。

加強過的 mirror 遞送機制 (這是方便下載的吧？我們好像用不到？)  
文件上能附加圖片。 (咦？以前不行嗎？沒注意過耶？) 
更新過的版本資訊獲取系統，這樣大部份的  Library 都會有版本資訊。 

我個人觀察到的如下：

樣式上有些許調整。 (好吧，這個不重要...|||orz) 
把目前常見的技術都編進去了。 (這個才是重點！)

果然手冊還是要人性化一點比較好。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p><a href="http://www.php.net/manual/en/">PHP 官方參考手冊</a>為了因應開發的潮流，作了一些改變。</p>
<ul>
<li>加強過的 mirror 遞送機制 (這是方便下載的吧？我們好像用不到？)  </li>
<li>文件上能<a href="http://tw.php.net/function.imagearc">附加圖片</a>。 (咦？以前不行嗎？沒注意過耶？) </li>
<li>更新過的版本資訊獲取系統，這樣大部份的  Library 都會有版本資訊。 </li>
</ul>
<p>我個人觀察到的如下：</p>
<ul>
<li>樣式上有些許調整。 (好吧，這個不重要...|||orz) </li>
<li>把目前常見的技術都編進去了。 (這個才是重點！)</li>
</ul>
<p>果然手冊還是要<a href="http://www.santosj.name/php/writing-manuals-for-users/">人性化</a>一點比較好。</p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2694690.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2694690.html</guid>
	<category> PHP</category>
	<pubDate>Sun, 04 Feb 2007 11:05:54 +0800</pubDate>
</item>
<item>
	<title>PHPUnit 3.0 正式發佈！！</title>
	<description><![CDATA[
			真是天大的好消息~~
PHPUnit 3.0
記得把以前的測試中，有用到 PHPUnit2_ 前置字元的地方，改成 PHPUnit_ ，其他 PHPUnit 3.0 就會幫你處理啦~~
新特色：

Mock Objects
Selenium Integration
Code-Coverage

可喜可賀~~
請參考： PHPUnit 3.0 RC1 發佈
		]]>
	</description>
	<content:encoded><![CDATA[
			<p>真是天大的好消息~~</p>
<p><a href="http://sebastian-bergmann.de/archives/638-PHPUnit-3.0.html">PHPUnit 3.0</a></p>
<p>記得把以前的測試中，有用到 PHPUnit2_ 前置字元的地方，改成 PHPUnit_ ，其他 PHPUnit 3.0 就會幫你處理啦~~</p>
<p>新特色：</p>
<ul>
<li>Mock Objects</li>
<li>Selenium Integration</li>
<li>Code-Coverage</li>
</ul>
<p>可喜可賀~~</p>
<p>請參考： <a href="http://blog.roodo.com/jaceju/archives/2445423.html">PHPUnit 3.0 RC1 發佈</a></p>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2502032.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2502032.html</guid>
	<category> PHP</category>
	<pubDate>Mon, 20 Nov 2006 21:35:37 +0800</pubDate>
</item>
<item>
	<title>PHP 裡的 Prototype-based 開發手法</title>
	<description><![CDATA[
			上次介紹了一篇 Bring some Ruby/Prototype flavour in your PHP array  ，這次有個類似的。
文章網址： Prototype-based programming in PHP

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>上次介紹了一篇 <a href="http://hasin.wordpress.com/2006/10/17/bring-some-rubyprototype-flavour-in-your-php-array/">Bring some Ruby/Prototype flavour in your PHP array</a>  ，這次有個類似的。</p>
<p>文章網址： <a href="http://personal.schmalls.com/2006/11/06/prototype-based-programming-in-php/">Prototype-based programming in PHP</a></p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/2451637.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2451637.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2451637.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 10 Nov 2006 14:29:00 +0800</pubDate>
</item>
<item>
	<title>PHPUnit 3.0 RC1 發佈</title>
	<description><![CDATA[
			如果你跟我一樣也是關注 PHPUnit 發展的開發者，那麼這個好消息想必你應該已經知道了。
PHPUnit 在 3.0 beta 後，從 PHPUnit2 轉回到 PHPUnit 上，而原來的 PHPUnit for PHP4 似乎就不再維護了 (PEAR 上也找不到) 。
註： SimpleTest 還是可以在 PHP4 上使用，我想這應該也是大部份 PHP 開發者喜歡用的一個單元測試框架。 
現在 RC1 也建議大家把原來在 PHPUnit2 上建立的測試，全部移轉到 PHPUnit 上。而在 PHPUnit 3.1 裡，就會直接把 PHPUnit2 裡面的類別全部改名了。所以呢， PHPUnit 就會統一對外的命名。
註：還有一個 PhpUnit ，這個不是 PEAR 官方推薦的套件，在 2005/10 以後就停止維護了。 
安裝 PHPUnit 3.0 RC1 很簡單，在 Command Line 下執行  (要先裝好 PEAR) ：
C:\>pear channel-discover pear.phpunit.de
C:\>pear install phpunit/PHPUnit-3.0.0RC1
這樣就可以了。
註：如果有安裝 pear.php.net 版的 PHPUnit 及 PHPUnit2 ，則要先將它們 uninstall 。 
 ChangeLog 也是必看的喔！ 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>如果你跟我一樣也是關注 PHPUnit 發展的開發者，那麼這個好消息想必你應該已經知道了。</p>
<p>PHPUnit 在 3.0 beta 後，從 PHPUnit2 轉回到 PHPUnit 上，而原來的 PHPUnit for PHP4 似乎就不再維護了 (<a href="http://pear.php.net/search.php?q=PHPUnit&amp;in=packages">PEAR</a> 上也找不到) 。</p>
<p class="note">註： <a href="http://www.lastcraft.com/simple_test.php">SimpleTest</a> 還是可以在 PHP4 上使用，我想這應該也是大部份 PHP 開發者喜歡用的一個單元測試框架。 </p>
<p>現在 RC1 也建議大家把原來在 PHPUnit2 上建立的測試，全部移轉到 PHPUnit 上。而在 PHPUnit 3.1 裡，就會直接把 PHPUnit2 裡面的類別全部改名了。所以呢， PHPUnit 就會統一對外的命名。</p>
<p class="note">註：還有一個 <a href="http://phpunit.sourceforge.net/">PhpUnit</a> ，這個不是 <a href="http://pear.php.net/">PEAR</a> 官方推薦的套件，在 2005/10 以後就停止維護了。 </p>
<p>安裝 PHPUnit 3.0 RC1 很簡單，在 Command Line 下執行  (要先裝好 <a href="http://pear.php.net/">PEAR</a>) ：</p>
<pre><code>C:\><strong>pear channel-discover pear.phpunit.de</strong>
C:\><strong>pear install phpunit/PHPUnit-3.0.0RC1</strong></code></pre>
<p>這樣就可以了。</p>
<p class="note">註：如果有安裝 pear.php.net 版的 PHPUnit 及 PHPUnit2 ，則要先將它們 uninstall 。 </p>
<p> <a href="http://www.phpunit.de/wiki/ChangeLog">ChangeLog</a> 也是必看的喔！ </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2445423.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2445423.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 09 Nov 2006 09:46:35 +0800</pubDate>
</item>
<item>
	<title>PHP 5.2.0 Win32 的 go-pear.phar 無法運作</title>
	<description><![CDATA[
			話說我在安裝 PHP 5.2.0 Win32 版後，想試著重新安裝 PEAR ，但是失敗了。出現的錯誤訊息如下：
Warning: Cannot use a scalar value as an array in phar://go-pear.phar/PEAR/Comma nd.php on line 268
但那時候為了要處理其他事情，就暫時把這件事擱置下來。
今天看到了 PHPWoman 上發表了一篇 Bundled go-pear.phar broken in 5.2 windows releases ，大意是說 Greg Beaver (PEAR Installer 的作者) 已經立刻修復這個錯誤，但是卻沒有把它併到 PHP 5.2.0 Win32 的釋出版本裡。
解決的方法是自己到 http://go-pear.org/ 去抓最新版的 go-pear.phar (把首頁內容另存新檔即可) ，或到 cvs 裡去抓也可以 (把第一個 download 連結另存新檔就是了) 。抓回來後放到 PHP 安裝目錄裡的 PEAR 資料夾內即可，然後就可以按照正常程序安裝了。 
註：這樣下載回來的 go-pear.phar 不包含壓縮過的 PEAR 基本套件，它會直接再從網路上下載。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>話說我在安裝 <a href="http://www.php.net/downloads.php">PHP 5.2.0 Win32</a> 版後，想試著重新安裝 <a href="http://pear.php.net">PEAR</a> ，但是失敗了。出現的錯誤訊息如下：</p>
<pre><code>Warning: Cannot use a scalar value as an array in phar://go-pear.phar/PEAR/Comma nd.php on line 268</code></pre>
<p>但那時候為了要處理其他事情，就暫時把這件事擱置下來。</p>
<p>今天看到了 <a href="http://www.phpwomen.org/">PHPWoman</a> 上發表了一篇 <a href="http://www.phpwomen.org/wordpress/2006/11/06/bundled-go-pearphar-broken-in-52-windows-releases/">Bundled go-pear.phar broken in 5.2 windows releases</a> ，大意是說 <a href="http://greg.chiaraquartet.net/">Greg Beaver</a> (PEAR Installer 的作者) 已經立刻修復這個錯誤，但是卻沒有把它併到 PHP 5.2.0 Win32 的釋出版本裡。</p>
<p>解決的方法是自己到 <a href="http://go-pear.org/">http://go-pear.org/</a> 去抓最新版的 go-pear.phar (把首頁內容另存新檔即可) ，或到 <a href="http://cvs.php.net/viewvc.cgi/pearweb/public_html/go-pear.phar?view=log">cvs</a> 裡去抓也可以 (把第一個 download 連結另存新檔就是了) 。抓回來後放到 PHP 安裝目錄裡的 PEAR 資料夾內即可，然後就可以按照正常程序安裝了。 </p>
<p class="note">註：這樣下載回來的 go-pear.phar 不包含壓縮過的 PEAR 基本套件，它會直接再從網路上下載。 </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2437099.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2437099.html</guid>
	<category> PHP</category>
	<pubDate>Tue, 07 Nov 2006 23:30:25 +0800</pubDate>
</item>
<item>
	<title>PHP SPL</title>
	<description><![CDATA[
			今天我正在試一個目錄搜尋的程式，想到了 PHP5 在 SPL (Standard PHP Library) 裡有定義了一個 DirectoryIterator 的類別。而在找尋相關資料時，發現了一個好站： PHP Wiki 。
PHP Wiki 介紹了很多 PHP 的資料與教學，我想對 PHP 玩家來說是個很不錯的參考網站。其中 SPL 分類裡更是提到了很多 SPL 內建類別的用法，讓我這個 PHP5 新手學到了很多有趣的東西。 
不過要小心一點： PHP 5.1 以後的 SPL 已經改了相當多，有些 PHP Wiki 的範例我在測試時會出現問題。比較好的方法是查看一下 PHP 手冊有關 SPL 的章節，並在轉換 PHP 版本時使用 get_declared_classes 及 get_declared_interfaces 來查看相關已定義的類別與介面。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>今天我正在試一個目錄搜尋的程式，想到了 PHP5 在 <a href="http://wiki.cc/php/SPL">SPL</a> (Standard PHP Library) 裡有定義了一個 <a href="http://wiki.cc/php/DirectoryIterator">DirectoryIterator</a> 的類別。而在找尋相關資料時，發現了一個好站： <a href="http://wiki.cc/php/">PHP Wiki</a> 。</p>
<p><a href="http://wiki.cc/php/">PHP Wiki</a> 介紹了很多 PHP 的資料與教學，我想對 PHP 玩家來說是個很不錯的參考網站。其中 <a href="http://wiki.cc/php/SPL">SPL</a> 分類裡更是提到了很多 SPL 內建類別的用法，讓我這個 PHP5 新手學到了很多有趣的東西。 </p>
<p>不過要小心一點： PHP 5.1 以後的 SPL 已經改了相當多，有些 PHP Wiki 的範例我在測試時會出現問題。比較好的方法是查看一下 PHP 手冊有關 <a href="http://www.php.net/manual/en/ref.spl.php">SPL</a> 的章節，並在轉換 PHP 版本時使用 <a href="http://tw.php.net/manual/en/function.get-declared-classes.php">get_declared_classes</a> 及 <a href="http://tw.php.net/manual/en/function.get-declared-interfaces.php">get_declared_interfaces</a> 來查看相關已定義的類別與介面。 </p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/2424579.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2424579.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2424579.html</guid>
	<category> PHP</category>
	<pubDate>Sun, 05 Nov 2006 17:43:05 +0800</pubDate>
</item>
<item>
	<title>PHP 5.2.0 釋出了</title>
	<description><![CDATA[
			順便貼一些 PHP 相關的新聞：

PHP 5.2.0 Released

New memory manager for the Zend Engine with improved performance and a more accurate memory usage tracking.
Input filtering extension was added and enabled by default.
JSON extension was added and enabled by default.
ZIP extension for creating and editing zip files was introduced.
Hooks for tracking file upload progress were introduced.
Introduced E_RECOVERABLE_ERROR error mode.
Introduced DateTime and DateTimeZone objects with methods to manipulate date/time information.
Upgraded bundled SQLite, PCRE libraries.
Upgraded OpenSSL, MySQL and PostgreSQL client libraries for Windows installations.
Many performance improvements.
Over 200 bug fixes.


PHP 5.2 UPDATE INFO
New help desk application using Zend Framework用 Zend Framework 開發桌面應用程式。
Testing PHP Applications with PHPUnit 3用 PHPUnit3 測試 PHP 應用程式的線上投影片。
phpMyAdmin - error.php XSS VulnerabilityphpMyAdmin 在 error.php 上的安全疑慮，會影響 2.9.0.2 以下的版本。
Graphical Interfaces and Unit Testing 圖形介面與單元測試。
Andrei Zmievski: Slides from Zend ConferenceAndrei Zmievski 在 Zend Conference 演說的投影片。

PHP 越來越有趣了...可是我為什麼還是得抱著 ASP 呀...|||orz 
		]]>
	</description>
	<content:encoded><![CDATA[
			<p>順便貼一些 PHP 相關的新聞：</p>
<ul>
<li><a href="http://www.php.net/">PHP 5.2.0 Released</a>
<ul>
<li>New memory manager for the Zend Engine with improved performance and a more accurate memory usage tracking.</li>
<li>Input filtering extension was added and enabled by default.</li>
<li>JSON extension was added and enabled by default.</li>
<li>ZIP extension for creating and editing zip files was introduced.</li>
<li>Hooks for tracking file upload progress were introduced.</li>
<li>Introduced E_RECOVERABLE_ERROR error mode.</li>
<li>Introduced DateTime and DateTimeZone objects with methods to manipulate date/time information.</li>
<li>Upgraded bundled SQLite, PCRE libraries.</li>
<li>Upgraded OpenSSL, MySQL and PostgreSQL client libraries for Windows installations.</li>
<li>Many performance improvements.</li>
<li>Over 200 bug fixes.</li>
</ul>
</li>
<li><a href="http://www.php.net/UPDATE_5_2.txt">PHP 5.2 UPDATE INFO</a></li>
<li><a href="http://www.dotvoid.com/view.php?id=66">New help desk application using Zend Framework</a><br />用 Zend Framework 開發桌面應用程式。</li>
<li><a href="http://sebastian-bergmann.de/archives/636-Testing-PHP-Applications-with-PHPUnit-3.html">Testing PHP Applications with PHPUnit 3</a><br />用 PHPUnit3 測試 PHP 應用程式的線上投影片。</li>
<li><a href="http://www.hardened-php.net/advisory_122006.137.html">phpMyAdmin - error.php XSS Vulnerability</a><br />phpMyAdmin 在 error.php 上的安全疑慮，會影響 2.9.0.2 以下的版本。</li>
<li><a href="http://www.devshed.com/c/a/PHP/Graphical-Interfaces-and-Unit-Testing/">Graphical Interfaces and Unit Testing </a><br />圖形介面與單元測試。</li>
<li><a href="http://www.gravitonic.com/blog/archives/000227.html">Andrei Zmievski: Slides from Zend Conference</a><br />Andrei Zmievski 在 Zend Conference 演說的投影片。</li>
</ul>
<p>PHP 越來越有趣了...可是我為什麼還是得抱著 ASP 呀...|||orz </p>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2412095.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2412095.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 03 Nov 2006 09:17:39 +0800</pubDate>
</item>
<item>
	<title>Zend 和 Microsoft 合作</title>
	<description><![CDATA[
			今天我訂閱的一些國外有關 PHP 的 Blog ，一直在報導 Zend 和 Microsoft 的相關文章。
這裡我把相關文章網址列出來，有興趣的朋友可以自己去看看：

PHP on IIS7 w/FastCGI
Annoucning: FastCGI tech preview available for IIS 5.1, 6 and 7
FastCGI for IIS
IIS 7 FastCGI Module
Zend Core (Windows Technology Preview)
Making PHP on Windows work!
Microsoft Announces Collaboration with Zend to Improve PHP on Windows and IIS


		]]>
	</description>
	<content:encoded><![CDATA[
			<p>今天我訂閱的一些國外有關 PHP 的 Blog ，一直在報導 Zend 和 Microsoft 的相關文章。</p>
<p>這裡我把相關文章網址列出來，有興趣的朋友可以自己去看看：</p>
<ul>
<li><a href="http://blogs.iis.net/bills/archive/2006/10/31/PHP-on-IIS.aspx">PHP on IIS7 w/FastCGI</a></li>
<li><a href="http://blogs.iis.net/bhill/archive/2006/10/31/Annoucning_3A00_-FastCGI-tech-preview-available-for-IIS-5.1_2C00_-6-and-7.aspx">Annoucning: FastCGI tech preview available for IIS 5.1, 6 and 7</a></li>
<li><a href="http://www.iis.net/default.aspx?tabid=1000051">FastCGI for IIS</a></li>
<li><a href="http://blogs.iis.net/rickjames/archive/2006/10/31/IIS-7-FastCGI-Module.aspx">IIS 7 FastCGI Module</a></li>
<li><a href="http://www.zend.com/products/zend_core/windows_preview">Zend Core (Windows Technology Preview)</a></li>
<li><a href="http://andigutmans.blogspot.com/2006/10/making-php-on-windows-work.html">Making PHP on Windows work!</a></li>
<li><a href="http://blogs.iis.net/bills/archive/2006/10/31/IIS-Team-Announces-FastCGI-For-IIS-5.1_2C00_-IIS-6.0-and-IIS7.aspx">Microsoft Announces Collaboration with Zend to Improve PHP on Windows and IIS</a></li>
</ul>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2399326.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2399326.html</guid>
	<category> PHP</category>
	<pubDate>Wed, 01 Nov 2006 09:58:03 +0800</pubDate>
</item>
<item>
	<title>PHP 開發最佳實踐</title>
	<description><![CDATA[
			說明
這兩天是 Zend 的研討會，有很多大師級人物主講。其中 Best Practices of PHP Development 是 10/31 號的一個議題，提到了一些在 PHP 開發上比較好的規則，大家可以參考看看。
其他還有很多不錯的議題，有空再去收集相關的資訊。
重點節錄

Source Documentation

PHPDoc is the defacto documentation standard, it can be parsed by PHPDocumentor and Doxygen 
Use @category and  @package to manage your documentation
Using PHPDoc allows all developers to immediately understand your code

Unit Testing

Focusing on PHPUnit
Test religiously
Without tests, code is fragile and will regress - there is nothing to tell you when you break your code.
You are not wasting time by creating tests, you're wasting time by peppering your code with var_dump() and trying to debug code manually.
Learning to write good object oriented code that is testable takes practice and discipline. Learn to design for usability. 
Test-First methodology allows the tests to become the specification of code you are writing. 
Using Classes is not Object Oriented Design

Source Control

Source control was on the benefits of using SVN to manage your code.
Learn to use tagging and branching instead of committing everything to HEAD 
Trac is cool (I caught up on emails during this section - great wifi) 

Deployment

Never edit code on the server
Check out tagged branches from your svc software
Deploy to a staging server on your production server, test first then modify the symlink.
Write acceptance and integration tests: http://manuals.rubyonrails.com/read/book/17)
Monitor Health of Servers: http://www.plope.com/software/supervisor/
Store schema of your database by committing the schema into your svc server - suggestion: http://www.mysqldiff.org/ and pre-commit hooks


參考網址

ZendCon 2006 Notes: Best Practices for PHP Development
Session Schedule

投影片下載
Best Practices of PHP Development

		]]>
	</description>
	<content:encoded><![CDATA[
			<h2>說明</h2>
<p>這兩天是 Zend 的研討會，有很多大師級人物主講。其中 Best Practices of PHP Development 是 10/31 號的一個議題，提到了一些在 PHP 開發上比較好的規則，大家可以參考看看。</p>
<p>其他還有很多不錯的議題，有空再去收集相關的資訊。</p>
<h2>重點節錄</h2>
<blockquote>
<h3>Source Documentation</h3>
<ul>
<li>PHPDoc is the defacto documentation standard, it can be parsed by PHPDocumentor and Doxygen </li>
<li>Use @category and  @package to manage your documentation</li>
<li>Using PHPDoc allows all developers to immediately understand your code</li>
</ul>
<h3>Unit Testing</h3>
<ul>
<li>Focusing on PHPUnit</li>
<li>Test religiously</li>
<li>Without tests, code is fragile and will regress - there is nothing to tell you when you break your code.</li>
<li>You are not wasting time by creating tests, you're wasting time by peppering your code with var_dump() and trying to debug code manually.</li>
<li>Learning to write good object oriented code that is testable takes practice and discipline. Learn to design for usability. </li>
<li>Test-First methodology allows the tests to become the specification of code you are writing. </li>
<li>Using Classes is not Object Oriented Design</li>
</ul>
<h3>Source Control</h3>
<ul>
<li>Source control was on the benefits of using SVN to manage your code.</li>
<li>Learn to use tagging and branching instead of committing everything to HEAD </li>
<li>Trac is cool (I caught up on emails during this section - great wifi) </li>
</ul>
<h3>Deployment</h3>
<ul>
<li>Never edit code on the server</li>
<li>Check out tagged branches from your svc software</li>
<li>Deploy to a staging server on your production server, test first then modify the symlink.</li>
<li>Write acceptance and integration tests: http://manuals.rubyonrails.com/read/book/17)</li>
<li>Monitor Health of Servers: http://www.plope.com/software/supervisor/</li>
<li>Store schema of your database by committing the schema into your svc server - suggestion: http://www.mysqldiff.org/ and pre-commit hooks</li>
</ul>
</blockquote>
<h2>參考網址</h2>
<ul>
<li><a href="http://www.phpdeveloper.org/news/6606">ZendCon 2006 Notes: Best Practices for PHP Development</a></li>
<li><a href="http://www.zendcon.com/speakers_list.php">Session Schedule</a></li>
</ul>
<h2>投影片下載</h2>
<p><a href="http://mikenaberezny.com/archives/60">Best Practices of PHP Development</a></p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2394732.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2394732.html</guid>
	<category> PHP</category>
	<pubDate>Tue, 31 Oct 2006 18:05:33 +0800</pubDate>
</item>
<item>
	<title>為 PHP 陣列帶來一點 Ruby/Prototype 的味道</title>
	<description><![CDATA[
			文章網址：Bring some Ruby/Prototype flavour in your PHP array
		]]>
	</description>
	<content:encoded><![CDATA[
			<p>文章網址：<a href="http://hasin.wordpress.com/2006/10/17/bring-some-rubyprototype-flavour-in-your-php-array/">Bring some Ruby/Prototype flavour in your PHP array</a></p>
		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/2314787.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2314787.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2314787.html</guid>
	<category> PHP</category>
	<pubDate>Tue, 17 Oct 2006 11:58:14 +0800</pubDate>
</item>
<item>
	<title>[好文] Building a simple MVC system with PHP5</title>
	<description><![CDATA[
			利用 PHP5 的特性，打造一個簡易的 MVC 系統。 
文章網址：Building a simple MVC system with PHP5 。
個人認為，這一篇看完之後，可以讓沒碰過 PHP5 的人或一知半解的人，對 PHP5 有進一步的瞭解。 

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>利用 PHP5 的特性，打造一個簡易的 MVC 系統。 </p>
<p>文章網址：<a href="http://www.phpit.net/article/simple-mvc-php5/">Building a simple MVC system with PHP5</a> 。</p>
<p>個人認為，這一篇看完之後，可以讓沒碰過 PHP5 的人或一知半解的人，對 PHP5 有進一步的瞭解。 </p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2053831.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2053831.html</guid>
	<category> PHP</category>
	<pubDate>Wed, 23 Aug 2006 10:13:01 +0800</pubDate>
</item>
<item>
	<title>[好文] Check your PHP code at every level with unit tests</title>
	<description><![CDATA[
			解釋如何利用 Unit Test 來測試各層級的 PHP 程式。
文章網址：Check your PHP code at every level with unit tests 
重點提示：

It's 3 a.m. Do you know if your code is still working?


		]]>
	</description>
	<content:encoded><![CDATA[
			<p>解釋如何利用 Unit Test 來測試各層級的 PHP 程式。</p>
<p>文章網址：<a href="http://www-128.ibm.com/developerworks/opensource/library/os-php-unit/">Check your PHP code at every level with unit tests</a> </p>
<p>重點提示：</p>
<blockquote>
<p>It's 3 a.m. Do you know if your code is still working?</p>
</blockquote>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/2045474.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/2045474.html</guid>
	<category> PHP</category>
	<pubDate>Mon, 21 Aug 2006 09:47:02 +0800</pubDate>
</item>
<item>
	<title>為 imageCreate 產生出來的圖設定連結</title>
	<description><![CDATA[
			這也是為 Tim 的網友回答的一篇：用  imageCreate 產生出來的圖怎麼設連結？
解這個問題之前，要先建立三個觀念：

 利用 imageCreate 或 imageCreateFromGif 建立的不是圖片，而是一個 PHP 的 Resource 而已，輸出圖片要用 imageGif 或同類型的圖片輸出函式。
 imageGif 輸出的格式是圖片 (Binary) ，而不是 HTML (Text) 。
 &lt;img src="xxx" /&gt; 中的 src 可以指向一個 php 程式 (事實上可以是任何輸出圖片格式的網址) 。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>這也是為 Tim 的網友回答的一篇：<a href="http://timteam.org/?TIM=FORUM&FORUM=1&ShowDocument=14350">用  imageCreate 產生出來的圖怎麼設連結？</a></p>
<p>解這個問題之前，要先建立三個觀念：</p>
<ol>
<li> 利用 <a href="http://tw2.php.net/manual/en/function.imagecreate.php">imageCreate</a> 或 <a href="http://tw2.php.net/manual/en/function.imagecreatefromgif.php">imageCreateFromGif</a> 建立的不是圖片，而是一個 PHP 的 Resource 而已，輸出圖片要用 <a href="http://tw2.php.net/manual/en/function.imagegif.php">imageGif</a> 或同類型的圖片輸出函式。</li>
<li> <a href="http://tw2.php.net/manual/en/function.imagegif.php">imageGif</a> 輸出的格式是圖片 (Binary) ，而不是 HTML (Text) 。</li>
<li> &lt;<a href="http://www.htmlhelp.com/reference/html40/special/img.html">img</a> src="xxx" /&gt; 中的 src 可以指向一個 php 程式 (事實上可以是任何輸出圖片格式的網址) 。</li>
</ol>
		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/1890151.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1890151.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1890151.html</guid>
	<category> PHP</category>
	<pubDate>Sat, 15 Jul 2006 15:40:38 +0800</pubDate>
</item>
<item>
	<title>[好文] PHP Security by Example</title>
	<description><![CDATA[
			透過實例介紹如何在 PHP 中寫出安全的程式，格式為 Flash 投影片。
連結：

PHP Security by Example 的英文說明。
PHP Security by Example 的投影片展示。
PHP Security by Example 的範例下載。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>透過實例介紹如何在 PHP 中寫出安全的程式，格式為 Flash 投影片。</p>
<p>連結：</p>
<ul>
<li><a href="http://shiflett.org/archive/241">PHP Security by Example 的英文說明。</a></li>
<li><a href="http://brainbulb.com/talks/php-security-by-example.swf">PHP Security by Example 的投影片展示。</a></li>
<li><a href="http://brainbulb.com/php-security-by-example.tar.gz">PHP Security by Example 的範例下載。</a></li>
</ul>
		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1858655.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1858655.html</guid>
	<category> PHP</category>
	<pubDate>Fri, 07 Jul 2006 09:25:20 +0800</pubDate>
</item>
<item>
	<title>PHP 小實驗 (2) - 正規表示式</title>
	<description><![CDATA[
			也是在 Tim Club 回答的問題，記在這裡自己備忘用。
一位網友問到，想把以下的文字：
[code:07318bb522][/code:07318bb522] 
[color=blue:8841ec98ad][/color:a76c137a60]
[b:8841ec98ad] [/b:6e4e964058]
[quote=&quot;Anonymous&quot;] [/quote:6e4e964058]
換成：
[code][/code] 
[color=blue][/color]
[b] [/b]
[quote] [/quote]
其實這個就是所謂的 BBCode ，只是我很少看過第一種表示形式。
怎麼轉換呢？

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>也是在 Tim Club 回答的<a href="http://timteam.org/?TIM=FORUM&FORUM=1&ShowDocument=14269">問題</a>，記在這裡自己備忘用。</p>
<p>一位網友問到，想把以下的文字：</p>
<pre><code>[code:07318bb522][/code:07318bb522] 
[color=blue:8841ec98ad][/color:a76c137a60]
[b:8841ec98ad] [/b:6e4e964058]
[quote=&quot;Anonymous&quot;] [/quote:6e4e964058]</code></pre>
<p>換成：</p>
<pre><code>[code][/code] 
[color=blue][/color]
[b] [/b]
[quote] [/quote]</code></pre>
<p>其實這個就是所謂的 BBCode ，只是我很少看過第一種表示形式。</p>
<p>怎麼轉換呢？</p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/1702001.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1702001.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1702001.html</guid>
	<category> PHP</category>
	<pubDate>Sat, 03 Jun 2006 11:26:32 +0800</pubDate>
</item>
<item>
	<title>PHP 小實驗 (1) - 等號的差異</title>
	<description><![CDATA[
			以後可能會三不五時測試一些小東西，以驗證自己的想法。
今天實驗的是以下的寫法會不會造成效能上的影響：
if ($x == TRUE) { //... }
常看到很多程式員會有這種寫法，我個人認為除非改用三個等號 (即全相等) 來強制認定 $x 一定要是布林值外，否則這是不必要的動作。因為如果有時候 $x 是非零整數值或非空字串的話，程式也還是會認為它是 TRUE ，不必特意用相等運算來判斷。 
if ($x === TRUE) { //... }

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>以後可能會三不五時測試一些小東西，以驗證自己的想法。</p>
<p>今天實驗的是以下的寫法會不會造成效能上的影響：</p>
<pre><code>if ($x == TRUE) { //... }</code></pre>
<p>常看到很多程式員會有這種寫法，我個人認為除非改用三個等號 (即全相等) 來強制認定 $x 一定要是布林值外，否則這是不必要的動作。因為如果有時候 $x 是非零整數值或非空字串的話，程式也還是會認為它是 TRUE ，不必特意用相等運算來判斷。 </p>
<pre><code>if ($x === TRUE) { //... }</code></pre>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/1373062.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1373062.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1373062.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 06 Apr 2006 12:15:54 +0800</pubDate>
</item>
<item>
	<title>很有趣的物件導向語言寫法</title>
	<description><![CDATA[
			在研究 Zend Framework Preview 的文件時，發現了一個很有趣的 PHP 寫法：
$select-&gt;from('round_table', '*')
       -&gt;where('noble_title = ?', 'Sir')
       -&gt;order('first_name')
       -&gt;limit(10,20);
看出來沒？除了 from 函式以外，每一個函式都直接接續著上一個函式。怎麼辦到的呢？

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>在研究 <a href="http://framework.zend.com/">Zend Framework Preview</a> 的文件時，發現了一個很有趣的 PHP 寫法：</p>
<pre><code>$select-&gt;from('round_table', '*')
       -&gt;where('noble_title = ?', 'Sir')
       -&gt;order('first_name')
       -&gt;limit(10,20);</code></pre>
<p>看出來沒？除了 from 函式以外，每一個函式都直接接續著上一個函式。怎麼辦到的呢？</p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/1221070.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1221070.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1221070.html</guid>
	<category> PHP</category>
	<pubDate>Tue, 07 Mar 2006 23:26:37 +0800</pubDate>
</item>
<item>
	<title>自行編譯 chm 格式的 PHP 手冊</title>
	<description><![CDATA[
			我常常會用到 PHP 手冊，其中 chm 格式支援了索引和搜尋的功能，是我比較喜歡的查詢方式。可是官方的 chm 手冊更新速度比較慢一點，因此隔一陣子我都會自行編譯 chm 格式的 PHP 手冊。
其實已經有對岸已經有一位名為「深空」的高手寫過這類的文章了，這裡我借用他的步驟，然後依循我自己的風格，重新寫一篇關於正體中文的版本。

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>我常常會用到 PHP 手冊，其中 chm 格式支援了索引和搜尋的功能，是我比較喜歡的查詢方式。可是官方的 chm 手冊更新速度比較慢一點，因此隔一陣子我都會自行編譯 chm 格式的 PHP 手冊。</p>
<p>其實已經有對岸已經有一位名為「深空」的高手寫過這類的<a href="http://www.openphp.cn/index.php/article/2/14/index.html">文章</a>了，這裡我借用他的步驟，然後依循我自己的風格，重新寫一篇關於正體中文的版本。</p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/1175357.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1175357.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1175357.html</guid>
	<category> PHP</category>
	<pubDate>Sun, 26 Feb 2006 15:49:35 +0800</pubDate>
</item>
<item>
	<title>哪個才是正確 PEAR 的安裝路徑</title>
	<description><![CDATA[
			大部份在 Windows 平台有安裝 PEAR 的人大概都知道以下兩種安裝方式 (以 PHP 5.1.2 為例) ：
X:\php&gt;go-pear.bat
以及，
X:\php\PEAR&gt;php go-pear.phar
(註：在 5.0 以前是用 go-pear.php) 
但是這兩種安裝方式的預設安裝路徑有些不同，這會影響 include_path 的設定！

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>大部份在 Windows 平台有安裝 PEAR 的人大概都知道以下兩種安裝方式 (以 PHP 5.1.2 為例) ：</p>
<pre><code>X:\php&gt;go-pear.bat</code></pre>
<p>以及，</p>
<pre><code>X:\php\PEAR&gt;php go-pear.phar</code></pre>
<p>(註：在 5.0 以前是用 go-pear.php) </p>
<p>但是這兩種安裝方式的預設安裝路徑有些不同，這會影響 include_path 的設定！</p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/1103405.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1103405.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1103405.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 09 Feb 2006 23:06:05 +0800</pubDate>
</item>
<item>
	<title>BOM (Byte Order Mark) 的問題</title>
	<description><![CDATA[
			如果在 Smarty 中 include 了 UTF-8 格式的檔案，就要小心 BOM (Byte Order Mark) 的問題。
BOM 的由來簡單來說是為了讓一些編輯程式能夠辨認該檔案是不是屬於 Unicode 格式，請參考 憤怒的青蛙: UTF-8, BOM, Micrisoft ，或用 Google 搜尋 UTF-8 BOM ，有更多有用的訊息。
那麼為什麼 BOM 會造成影響呢？因為 BOM 對 HTML 來說是屬於字元，所以 include UTF-8 的檔案時，HTML 就會就會認為被 include 的子樣版上方有個字元，因此就會保留一個空間給它了，就是你們看到那個白白的空行。
補充：這個空白行似乎只有 IE 才會出現。
這種問題也會發生在 PHP 上面，如果有使用 Session 時，常會見到以下情況：
Warning: session_start() [http://www.php.net/manual/en/function.session-start]:
 Cannot send session cookie -
 headers already sent by (output started at test.php:1) in test.php on line 2
而這也是 BOM 在做怪，原程式如下：
(BOM在這裡，但你看不見它)&lt;?php
session_start();
?&gt; 
解決的方式可以改用 EditPlus 、 EmEdit 等可支援無 BOM 之 UTF-8 的文字編輯器，如果是 Dreamweaver MX 2004 的話，在編碼方式選成 Unicode (UTF-8) 時就要將取消「包含 Unicode 簽名 (BOM) 」。 


		]]>
	</description>
	<content:encoded><![CDATA[
			<p>如果在 Smarty 中 include 了 UTF-8 格式的檔案，就要小心 BOM (Byte Order Mark) 的問題。</p>
<p>BOM 的由來簡單來說是為了讓一些編輯程式能夠辨認該檔案是不是屬於 Unicode 格式，請參考 <a href="http://blog.cdpa.nsysu.edu.tw/zmx/archives/001058.html" target="_blank">憤怒的青蛙: UTF-8, BOM, Micrisoft</a> ，或用 Google 搜尋 <a href="http://www.google.com.tw/search?hl=zh-TW&amp;rls=GGGL%2CGGGL%3A2005-09%2CGGGL%3Azh-TW&amp;q=utf-8+bom&amp;btnG=%E6%90%9C%E5%B0%8B&amp;meta=lr%3Dlang_zh-TW" target="_blank">UTF-8 BOM</a> ，有更多有用的訊息。</p>
<p>那麼為什麼 BOM 會造成影響呢？因為 BOM 對 HTML 來說是屬於字元，所以 include UTF-8 的檔案時，HTML 就會就會認為被 include 的子樣版上方有個字元，因此就會保留一個空間給它了，就是你們看到那個白白的空行。</p>
<p class="note">補充：這個空白行似乎只有 IE 才會出現。</p>
<p>這種問題也會發生在 PHP 上面，如果有使用 Session 時，常會見到以下情況：</p>
<pre><code>Warning: session_start() [http://www.php.net/manual/en/function.session-start]:
 Cannot send session cookie -
 <font color="#FF0000">headers already sent by</font> (output started at test.php:1) in test.php on line 2</code></pre>
<p>而這也是 BOM 在做怪，原程式如下：</p>
<pre><code><font color="#FF0000">(BOM在這裡，但你看不見它)</font>&lt;?php
session_start();
?&gt; </code></pre>
<p>解決的方式可以改用 EditPlus 、 EmEdit 等可支援無 BOM 之 UTF-8 的文字編輯器，如果是 Dreamweaver MX 2004 的話，在編碼方式選成 Unicode (UTF-8) 時就要將取消「包含 Unicode 簽名 (BOM) 」。 </p>
<p><img src="http://jaceju.staff.doubleservice.com/tutorial/bom/dw_bom.gif" alt="Dreamweaver BOM" width="621" height="344" /></p>

		
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1100799.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1100799.html</guid>
	<category> PHP</category>
	<pubDate>Thu, 09 Feb 2006 11:31:15 +0800</pubDate>
</item>
<item>
	<title>PHP 小陷阱</title>
	<description><![CDATA[
			最近做一個電子報排程的程式，原本是在 PHP 5 上開發，後來轉到安裝 PHP 4 的正式機上時發生了一些問題。以下是我的記錄：

		]]>
	</description>
	<content:encoded><![CDATA[
			<p>最近做一個電子報排程的程式，原本是在 PHP 5 上開發，後來轉到安裝 PHP 4 的正式機上時發生了一些問題。以下是我的記錄：</p>

		<a class="acontinues" href="http://blog.roodo.com/jaceju/archives/1017394.html">(繼續閱讀...)</a>
		]]>
	</content:encoded>
	<link>http://blog.roodo.com/jaceju/archives/1017394.html</link>
	<guid>http://blog.roodo.com/jaceju/archives/1017394.html</guid>
	<category> PHP</category>
	<pubDate>Wed, 18 Jan 2006 11:27:50 +0800</pubDate>
</item>
</channel>
</rss>