2009年12月30日 星期三

php 物件的static method最好要以static keyword清楚標示

因為一時心血來潮  想知道呼叫php物件的 static method 跟 non-static method 在效率上有沒有差別
就寫了簡單的程式測試一下  一開始我的物件的method只有一個 並沒有以 static 關鍵字宣告:
class T
{
    public f()
    {
    }
}

而只是以兩種不同的方式呼叫:
1.
$o = new T();
$o->f();

2.
T::f();

結果以第二種方式 花的時間大概是 第一種方式的兩倍 讓我非常驚訝
後來我在php官網發現了造成效率差距這麼巨大的原因
Calling non-static methods statically generates an E_STRICT level warning.

即使在 php.ini 中的 error_reporting 設為 E_ALL 用第二種方式呼叫 method也不會出現 warning
因為 E_ALL 是不包含 E_STRICT 的  所以我便以為這樣寫的 code 是合法的 真是大錯特錯

我後來把 class 改寫:
class T
{
    public function f()
    {
    }

    public static function sf()
    {
    }
}

再以 T::sf() 呼叫 static method
結果是呼叫 static method 或是 non-static method 時間都差不多 感覺這樣才是合理的狀態

然後 我把 error_reporting 改成 E_ALL | E_STRICT 了
寫 code 還是要嚴謹一點才好

2009年9月12日 星期六

windows的handle

這裡有說明了 windows 系統中的 handle 代表的意義
windows kernel 幫每個 process  維護一份 handle table
table 中的 entry 指向該 handle 所代表的 object
因為是每個 process 一份 handle table 所以一個 handle value 只對使用該 handle 的 process 有意義

2009年8月15日 星期六

PHP的物件

最近練習用PHP寫聊天室來當做練習  參考網路上的文章用MVC與物件來寫程式 這是第一次用物件寫程式
之前一直很想知道程序導向與物件導向的優異在哪  但是我程式寫的不夠多  即使查了很多資料但始終無法體會
這次用物件來寫程式 對於物件的優點還是沒有什麼體會 不過倒是學到了許多以前不知道的知識
以下做一些筆記:


magic method
PHP物件有許多 magic method 可以用 例如 __call method
例如 假設有個情況是我要把client傳來的字串直接當作method name去呼叫某物件的method
但是 client 輸入的資料是一定要檢查的 我可以用 method_exists 去檢查此 method 存不存在
但是如果用 __call 的話 直接將呼叫不存在的method時該做的動作寫在 __call 裡就可以了

此外 __get __set 也是很好用的 method
看到這兩個 method 我才知道 PHP 物件也可以像 javascript 一樣動態創建屬性
不過我一直很想知道 如果物件沒有覆寫這兩個method的話 動態創建屬性時的行為會是怎樣
PHP官網似乎沒有提到這個 自己實驗的結果 只知道物件會自動創造一個 public 屬性
這樣當然很方便 但是依賴這種寫法 感覺以後維護或是 debug 會很有問題
(因為動態創建的屬性與 class 中 define 的屬性的存取都是一樣寫法 會分不清楚)
在網路上也看到其他人自訂 setvar getvar 之類的method來動態存取屬性


XML的處理
我的資料有些是使用 xml 檔案來儲存 PHP 可以用 simplexml 系列的函式去處理 xml 檔案
一開始其實我是想用 DOMDocument 來處理的 因為這個物件對 xml 的存取與處理很完善
但是在試用的時候發現找不到 DOMDocument 物件 雖然官網說這個物件是 PHP5 core 的一部份(我server是PHP5)
查了資料才發現 這是 linux distribution dependent 的 有些 linux 版本PHP5就是沒有 DOMDocument
必須要多裝 php-xml 才行
所以我只好什麼事情都用 simplexml 來做 這個物件真的是夠 simple 連 removeChild 這種 method 都沒有
後來我發現可以用 unset 來直接刪掉節點 上網搜尋的結果也是通通都用 unset 去刪掉節點
因為 xml 是普通文字檔案 需要做同步的機制 我又用了 semaphore 去做存取控制
雖然有 flock 可以鎖住檔案 但是官網有人回報有問題 所以不太敢用


物件的使用
對於 PHP 物件的使用熟悉了一點 像是 $this 變數 static 關鍵字 還有 :: 運算子的用途都稍有瞭解
還發現 PHP5 支援 type hinting 這個機制
可以在 function prototype 指定接收參數是哪種物件或是陣列 例如:

function foo_arr(array $arr) {};

function foo_obj(some_class $obj) {};

則之後呼叫到這樣定義的函式時 只能傳物件(而且必須是 "some_class" 的物件) 或是陣列過去
這個機制感覺蠻好玩的 不過現在只支援物件與陣列

2009年8月7日 星期五

apache mod rewrite

要使用 apache 的 mod rewrite 功能 在設定檔中必須要設定 Options FollowSymLinks
apache官方文件中就有描述
如果不是網站管理員的話  只要在http.conf有設定AllowOverride All
則可以將 Options FollowSymLinks 放到網頁資料夾底下的.htaccess檔案中
這樣也可以使用 mod rewrite 的功能

此外 修改.htaccess的設定後 不需要重新啟動apache即可立即生效
因為apache會在每次http request發生時去掃瞄資料夾下的.htaccess檔案
這提供了相當方便的功能 (修改完立即見效)
但也犧牲了一些效能 (每次都要掃瞄.htaccess檔案)

2009年8月6日 星期四

linux linker and dynamic linker

在linux下面的linker是ld
這是在編譯時 將各個object file連結成一個executable的程式

而linux下面的dynamic linker是ld.so/ld-linux.so
這是在一個程式要執行時 將程式與它所用到的dynamic share libraries連結起來並載入記憶體的程式
ld.so是用來處理a.out格式的二進位檔 ld-linux.so是用來處理ELF格式的二進位檔

從檔名可以看出來 dynamic linker是以share object的形式存在
當一個executable要開始執行時 dynamic linker 連結完executable與它用到的dynamic share libraries後 還會被map到該executable的address space中
因為ELF程式的PLT GOT機制 在程式執行中 還必須要用到dynamic linker

在Windows中的dynamic linker與linux不同 是以kernel的一部分存在
這樣做的好處是速度會快一點(不需要每個程式執行時都要將dynamic linker map到process address space中) 但是會缺少一點彈性

2009年7月24日 星期五

PHP裡的 & 運算子

在PHP中 下面這段寫法並不會出現警告訊息
< ?php
$a=&$b;
? >

這也許會讓人覺得 $b 變數未宣告即使用 應該會出現警告才對
但是在PHP官網裡的 What References Do有這一段說明:
Note: If you assign, pass, or return an undefined variable by reference, it will get created.

所以 當 &$b 出現時 $b 就會被創造 並且設為NULL 然後將 $a 設為 $b的 alias
因此上面的寫法在PHP裡 其實是合法的

不過PHP裡還有我較有疑問的地方是 只要一個變數設為NULL 則使用不存在的index也不會有事 例如:
< ?php
$a=NULL;
$b=$a['aaa']['bbb'];
? >
以上的寫法 在PHP中是不會出現警告訊息的 這是蠻讓人奇怪的一點

2009年7月23日 星期四

當網頁裡event發生時 阻擋default action的執行

在網頁裡 一個event發生時 通常會有default action
例如在一個text element中打字 則會發生 onkeydown onkeypress onkeyup這三個事件
default action就是在輸入框裡顯示打入的字串

想要阻止瀏覽器的default action執行時 如果是用inline的方式註冊event handler 直接return false就可以了
例如 < input type="text" onkeypress="return false;" >

但如果使用addEventListener註冊 event handler 就需採用別的方法 而且IE和firefox必須用不同的方法
例如:
< input type="text" id="text_element" >

< script type="text/javascript" >
function foo(e)
{
if (e.preventDefault)
e.preventDefault(); //firefox
else
e.returnValue=false; //IE
}
document.getElementById('text_element').addEventListener('keypress', foo, false);
< /script >

W3C的標準是用event object的preventDefault method去阻擋掉default action的發生
但是IE並沒有實作這個method 不過IE的event object有returnValue這個property
將這個屬性設為false一樣可以阻擋掉default action的發生
因此可以用上面的寫法去支援IE與firefox

2009年6月30日 星期二

javascript RegExp object literal syntax

今天看到一段javascript code 長的像下面這樣
if (/pattern/i.test(str))
//do something

一開始我看不懂/pattern/i到底是什麼東西
查了以後才知道 原來這是正規表示式物件的實體語法(RegExp object literal syntax)
之前只知道javascript有陣列實體語法 例如
var a=[1, "kerker", 555];

還有物件實體語法例如
var o={
p1 : 1,
p2 : "kerker",
p3 : {pp1:1, pp2:2} //巢狀物件
};

這些語法已經很方便了 但是我沒有想到javascript還有RegExp物件的實體語法!!
我有一瞬間震驚了 想不到javascript這麼方便阿...
不過也許這事廣為人知的 只是我太孤陋寡聞/_\(JavaScript:The Definitive Guide不知道拿到多久了 完全沒有好好看過 冏)

恩..javascript 真的是一個很不錯的語言阿

script tag的defer屬性

當瀏覽器瀏覽網頁時 他會一邊parse HTML code並顯示出來 一邊parse script標籤中的script code並執行
然而 在使用script標籤時 若是加上defer屬性 像這樣 < script defer="defer" >
則瀏覽器會在整個頁面都load完成後才開始去parse此標籤內的script code並執行
如果在script tag中的code都是function之類的 不會改變頁面內容的code的話 則加上defer屬性可以加快頁面被顯示的速度
defer屬性是HTML4的標準 FX跟IE現在都支援此屬性

2009年6月27日 星期六

mysql subquery

mysql select語句中加上 limit x 就可以限制查詢最多回傳x筆資料
但是如果需要的情況是 只想查詢資料表中的第1~第50筆那要怎麼辦
這可以用mysql的子查詢語法來達成 例如

select * from (select * from table1 limit 50) as derived_table where id!='kerker';

括號中間的select語句會先做查詢 然後回傳第0~49筆資料 接著外面的select再從這50筆資料作查詢
需要注意的是必須要給一個alias name(也就是上面的devived_table)給derived table才是合法的查詢

2009年6月12日 星期五

variable-length array

本來的C語言(C99之前)是不能用變數來宣告陣列長度的 例如:
int i[length];

後來C99標準中允許了這樣的宣告方式 但是C++並沒有這樣的標準
C++的動態陣列還是使用vector比較好

http://www.clarkcox.com/blog/?p=74#footnote_0_74
這裡有一篇文章寫到VLA的壞處 當stack pointer指到不正確的地方時 程式會發生什麼事沒人知道
這的確是直得思考的地方

另外 要將多維陣列傳給函式當參數時 除了第一維的維度可以不給之外 其餘都要給
例如 int func(int array[][4]); 這樣的寫法

2009年6月9日 星期二

client端執行filesystemobject

很久之前試過在client端執行filesystemobject去做寫檔的動作
當時IE跳出提示訊息 而只要使用者同意 就可以執行
最近聽說為了安全性 現在IE已將adodb.stream或是shell.application這類activex物件禁止

於是我用以下code試著在client端做寫檔的動作
dim fso
set fso=createobject("Scripting.FileSystemObject")
set test=fso.createtextfile("C:\\test.txt", true)
test.writeline("kerker")
test.close

網頁沒有提示 什麼都沒有發生 看來是已經禁止了
後來找到原因 是IE把設定改掉了
只要到網際網路選項->安全性->自定等級->起始不標示為安全的activex控制項 改成提示
再次執行 IE就跟上次一樣 跳出提示訊息 同意後 這段code就成功執行了

2009年6月2日 星期二

javascript event 傳播

javascript事件傳播流程 資料來源:w3c school

事件傳播

在 2 級 DOM 中,事件傳播分為三個階段:
第一,捕獲階段。事件從 Document 對象沿著文檔樹向下傳遞給目標節點。如果目標的任何一個先輩專門註冊了捕獲事件句柄,那麼在事件傳播過程中運行這些句柄。
第二個階段發生在目標節點自身。直接註冊砸目標上的適合的事件句柄將運行。這與 0 級事件模型提供的事件處理方法相似。
第三,起泡階段。在此階段,事件將從目標元素向上傳播回或起泡回 Document 對象的文檔層次。

http://www.quirksmode.org/js/events_order.html
這裡有詳盡的解釋

2009年5月19日 星期二

html input tag的image type

input tag的type屬性裡可以是image 然後可以用image tag的屬性
而且如果type是image 則這個input tag會有submit form的功能

2009年5月7日 星期四

javascript讀取CSS樣式

在javascript中用object.style只能讀到HTML element的行內樣式
要讀取一個HTML element所有的css樣式

在IE中可以用object.currentStyle 這是read-only的

在firefox中可以用window.getcomputedstyle(element, pseudoElt)

用簡單的判斷式就可以跨瀏覽器:
if (object.currentStyle)
do something
else if (window.getcomputedstyle)
do something

2009年4月19日 星期日

在HTA裡listen COM物件的event

找了很久在HTA裡listen COM物件的event 根據再網路上找到的資料 應該只有一個方法
就是利用< object> tag 語法如下:
< object id="myobj" classid="clsid:......">
< /object>

< script language="vbscript" for=myobj event=event_in_myobj>
//your event handler code
< /script>

以這種方式就可以撰寫自己的event handler
但是 因為我想要去操作的是webbrowser control或是internetexplorer object
我成功的listen到了webbroswer control物件的event
但是一但這個webbrowser control物件navigate到某個url之後
因為cross-frame security restrictions的問題 (網址)
就無法再去操作這個物件

沒試過internetexplorer物件 但是我想應該也是一樣的情況
所以想要在HTA裡listen webbrowser物件或是internetexplorer物件的event
又要不斷的讓這個物件navigate到不同的url 應該是沒辦法吧
殘念..

2009年4月17日 星期五

在vbscript中使用winhttprequest物件的小事項

在vbscript中 使用winhttprequest物件時 如果用POST送出request的話 參數一定要大寫, 例如
httpobj.open "POST", "url", false
如果用
httpobj.open "post", "url", false
server是接不到post過去的參數的
而且在send之前不要忘了加上setrequestheader "Content-Type", "application/x-www-form-urlencoded"這一行
不然server也是接不到參數
另外 如果用winhttprequest物件發出request到某個server去 而這個server會設定cookie
則接下來再發出request到同樣的server winhttprequest物件會自動幫你在header裡加上server設定的cookie
(如果沒有重新create出一個winhttprequest物件來用的話)
就像瀏覽器幫你做的事情一樣

一開始我只以為winhttprequest物件只是可以單純用來發出http request而已
沒想到他還這麼貼心的可以自動加cookie上去
真是有趣的發現

2009年4月16日 星期四

Temporary Internet Files

MS IE瀏覽器的Temporary Internet Files資料夾是一個很特別的資料夾
而且 它也許不是一個真正的資料夾
我在vbscript中去存取這個資料夾 發生了一些奇特的現象
例如我找不到它實際的路徑 即使用COM的shell物件拿到Temporary Internet Files的物件
也不能將檔案寫入這個資料夾 也不能用parsename method去拿這個資料夾裡面的檔案
同樣式special folder的desktop資料夾就不會這樣
這讓人還蠻想要去了解它到底是怎樣運作的 能知道怎麼使用Temporary Internet Files的
應該只有IE吧

此外 用filesystemobject物件去拿到的folder物件
以及用com shell物件的namespace拿到的folder物件
是不一樣的東西 雖然都叫做folder物件 但卻有不同的property和method
一開始讓我混淆了一下

HTA與vbscript

MS的vbscript可以在不同的host環境中執行 一般我們寫.vbs副檔名的檔案
通常是在wscript.exe或是cscript.exe這兩個環境中執行
在wscript.exe中執行時 就會有vbscript programmer都很熟悉的Wscript物件可以使用

但是這在HTA中是不行的 因為.hta檔案是在mshta.exe環境中執行
在這個環境中並沒有Wscript可以使用
就是因為這個原因 讓我在最近寫一個HTA文件時遭遇了很大的挫折

要解釋這件事情 得先說說createobject以及wscript.createobject這兩個函式
在vbscript中 這兩個函式可以create出一個COM物件讓programmer使用
但是這兩個函式其實是 不 一 樣 的
作為vbscript內建的createobject function 有兩個參數
第二個參數可以指定你要把這個物件create在哪台電腦上 也就是說可以遠端電腦裡create一個物件
例如 set obj=createobject("someobject", "remote_host_name")
這樣會在remote_host_name這台電腦裡創出一個物件來使用

而作為wscript物件的createobject method 也有兩個參數
第二個參數是作為programmer自己撰寫的event handler的prefix
例如 set obj=wscipt.createobject("internetexplorer.application", "ie_")
則接下來就可以用
sub ie_beforenavigate()
//some code
end sub
去listen internetexplorer物件的beforenavigate event了

這真是十分的好用 但是很可惜的是在HTA裡並沒有Wscript物件
因此也就沒有wcript.createobject可以用了

我想在HTA裡面 也可以用自己的event handler去listen某個COM物件的event
不過至今還沒有找到方法

不過 雖然不在wscript.exe裡面就沒有wscript物件可以用
並不表示以wscript為prefix的物件也不能用
例如wscript.shell物件 這個物件和wscript物件是分開的
即使環境不是在wscript.exe中 也可以用createobject("wscript.shell")去建立這個物件
這有時候是一件很容易讓人困惑的事情

2009年4月11日 星期六

microsoft vbscript與標準javascript的某些不同

microsoft發展的vbscript與標準的javascript有一些不同之處先說用vbscript來操作DOM物件在標準的javascript中要取得一個DOM物件 可以用getElementById、getElementsByName、getElementsByTagName這三個document物件的method不過在vbscript中要取得一個DOM物件就不需要那麼麻煩了只要一個DOM物件有設定id屬性或是name屬性 直接就可以操作他 如以下範例
< html >
< head >
< script language="VBScript">
sub myfunc()
myinput.value="kerker"
end sub
< /script >
< /head >
< body >
< input type="text" name="myinput" >
< input type="button" onclick="myfunc" value="test" >
< /body >
< /html >
在一個網頁裡的DOM物件可以有相同的name屬性值想操作這些物件 標準的作法是用document.getElementByName()來返回一個array去操作但在vbscript中 那個name屬性值就已經是一個array可以讓你操作物件 如下範例
< html >
< head >
< script language="VBScript" >
sub myfunc()
myinput(0).value="kerker"
myinput(1).value="kerker"
end sub
< /script >
< /head >
< body >
< input type="text" name="myinput" >
< input type="text" name="myinput" >
< input type="button" onclick="myfunc" >
< /bdoy >
< /html >
雖然vbscript這麼方便 但是也可以用getElementById來返回DOM物件不過這個method不只會搜尋DOM物件的id屬性 也會搜尋name屬性 若是有同樣name屬性值的DOM物件它只會返回第一個搜尋到DOM物件這在firefox是不會發生的 也許是IE不夠支援標準所致

其他vbscript較與眾不同的地方是 呼叫sub程序時不可以加括號 除非使用call去呼叫sub程序而呼叫function時括號則可加可不加 但是如果要使用function回傳值時則一定要加括號也因為sub不用加括號的關係 所以可以有onclick="myfunc"這種寫法標準的javascript是不行這樣寫的 一定要onclick="myfunc()"才行

2009年4月2日 星期四

vbscript download binary

之前碰到學長想要在windows上寫個程式可以有類似wget的功能
想到的方法是用vbscript去呼叫windows版本的wget
後來上網查了資料 才發現原來vbscript自己就可以做下載檔案的功能
只要用WinHttp.WinHttpRequest.5.1物件發出http request到伺服器
再用adodb.stream物件去接伺服器回傳的檔案就好了 只是似乎有檔案大小的限制
只能下載500MB之內的檔案 我猜這是因為他的作法是先將接到的row data放在heap段
再一次寫到disk中 所以檔案太大時記憶體就爆了

我越來越覺得vbscript很好很強大 尤其是它可以呼叫COM物件來做事
一直很懷疑vbscript是不是只有msgbox inputbox這種陽春的GUI元件可以用
結果當然不是
希望有時間可以研究用vbscript寫出視窗程式 一定會非常有趣

2009年3月25日 星期三

PHP雙引號內放置變數

在PHP中字串可以用單引號或是雙引號包起來 但是在使用雙引號內的字串時
PHP會先parse字串內有無變數 若是有變數則會將變數代換為變數的值
例如:
$a=123;
$b="kerker$akerker";
則$b其實是等於"kerker123kerker"

這樣在寫code時是有他的方便性 但是這種設計並不適用於中文字
例如:
$a=123;
$b="科科$a科科";
echo $b;
這樣只會印出 科科 而已

2009年3月18日 星期三

C++ global getline and cin.getline

C++ 有兩種getline 可以用
一種是在string STL library中的getline函式
這個函式是將讀到的整行字串(去掉linefeed)存到型態為string的變數中

而cin.getline則是將讀入的整行字串(一樣 去掉linefeed)存到型態為char *的C-style的變數中

附帶一提
在linux上也有自己的getline 在stdio.h函式庫中
這是GNU extension 不包含在標準C語言的stdio.h函式庫中

2009年2月10日 星期二

linux socket API: accept() Invalid argument

在使用linux socket API accept()時出現了error: Invalid argument
我的server是寫成concurrent的 用create thread的方式
上網找了資料 發現有人也有一樣的error message 他用fork child process的方式寫concurrent server
但神奇的是 只要把fork動作拿掉 accept()就不會出現error
我在我的multi thread server下試 沒錯 把create thread動作去掉 accept就成功

難道不讓人寫concurrent server了阿? 網上有人甚至懷疑是系統的問題
不死心 再找資料 結果發現有人說accept第三個參數 最好要先初始化 不然會有問題
我試了之後 accept()成功了!!!(驚)
man 了 accept()這個API 結果在man page裡就有說第三個參數要初始化= =
真是, 困擾我近一天的bug就這樣解了= =
不過為什麼會在未初始化的狀態下 concurrent會出錯而iterative就不會出錯?
這可能要去看accept的實作才會知道吧!