??ASP是Microsoft於較早推出的動態網頁程式設計技術,但其結合ADO對資料庫方便快速的存取、結合XML、COM/ActiveX等其它技術實現伺服器多層結構的功能使它在今天還有著頑強的生命力,而且依然有著一定的發展。 ASP.Net雖然在架構上完全不同於ASP,但它許多內建物件也是基於ASP來擴充的。網路上有無數的介紹ASP的文章,卻鮮有介紹ASP物件導向以及與其它語言比較的,這也就是我下定決心寫這篇文章的原因。
??因為是早期的版本,ASP只提供了很弱的物件導向的介面。眾所周知,ASP的實作語言分為VBScript和JavaScript/JScript: 在VBScript中有Class關鍵字,可以用來宣告一個自訂類別;JavaScript就比較怪,它用一個函數來「宣告」類,然後在這個函數裡透過this.prototype定義屬性,this.func定義方法。這裡將以VBScript為主進行討論,VBScript的類別聲明是這樣的:
??Class name
?? statements
??End Class
??這裡statements裡可以宣告公有或私有的成員,包括函數、成員和屬性。關於屬性,不得不讚一下微軟的get和set方法,這個在COM中出現的理念,直到.Net中一直被沿用下來,個人認為對程式設計師而言,比Java用getProp()、setProp()兩個方法來實現同樣效果要方便直觀得多。
??相較之下,VBScript中的類別與PHP4中的類別各有千秋(當然跟最新的PHP5沒法比),VBScript中的類別保持了VB的不完全面向對象的“特性”,它僅僅實現了最基本的建構/析構函式、成員函式、變數、屬性,甚至建構子不能帶參數。 PHP4中則也實作了繼承、函數重載等類別的重要性質,也只有實作了這些,才能稱之為物件導向,才有可能為實作多型提供基礎。但二者均沒有實現類別的靜態(static)成員等功能。儘管可以用其它一些變通達到同樣的功效,但從面向對象的思想出發,這都是不徹底的(由於PHP非常靈活,PHP4中可以通過成員函數的靜態變量來間接實現類的靜態變量;而“ ::”—— 可以實現類別的靜態函數訪問的操作符——在PHP4中沒有嚴格檢查。換句話說,所有的成員函數都可以當成靜態函數訪問,只要你在該函數裡不使用成員變數就不會出錯。所以在平常的使用中,你可以使用VBScript的自訂類別來封裝一些操作,但不要指望它像C++ / Java / .Net那樣為你的物件導向思想服務。
??VBScript同樣發揚了VB中預設的參數或變數是引用的好風格。這樣,儘管Script語言中對型別不敏感,但它也能夠達到C/C++裡指標/引用同樣的功效,完成很多事情。最基本的,比如說用它定義一個列表(List)的節點類別ListNode:
<%
Class ListNode
Public Content
Public NextNode
Private Sub Class_Initialize()
Content="Node"
Set NextNode=Nothing
End Sub
End Class
%>
??呵呵,就這麼簡單,但不要感到鄙夷,也不要忘記對變數初始值。 VB中也差不多,聲明時加上類型就行了。而使用時:
<%
Set nh=new ListNode
Set nh.NextNode=new ListNode
'其它語句…
'遍歷列表
Set n=nh
While Not n is Nothing
Response.Write n.Content+"<br />"
Set n=n.NextNode
Wend
%>
??如果不加其它程式碼,上面的運行結果是兩個“node”。 VBScript的自訂類別和物件也不外如是,只要掌握基本的概念,對它有一定了解,就再簡單不過了。再次強調,用Set語句來對物件進行賦值,相當於Java裡的賦值,都是得到一個引用。這比PHP4裡預設物件賦值是呼叫拷貝建構函式來創建一個新的物件好多了(甚至連obj=new Obj;這樣的語句都會創建兩個物件!如果你想獲得引用的話,要在等號後變量前顯示地加上&),而似乎PHP5也不想修改PHP4的這種做法。
??ASP中的Session本身是可以儲存物件的,它可以保存基本變量,數組,自動化物件(Automation Object)等,但在儲存自訂類別的物件時會碰到問題。如下面的程式碼:
<%
If isempty(Session("node")) Then Set Session("node")=New ListNode
Set n=Session("node")
Response.Write n.Content
%>
??還是上面的ListNode這個類,這段程式碼意圖在一個使用者會話中只保留一個ListNode的物件。所以當使用者第一次造訪該網頁時,會產生ListNode的一個對象,並保存在Session(“node”)中;後面造訪該網頁時,因為Session(“node”)不為空了,所以不會產生一個新的對象,而是到Session(“node”)中取出已儲存的對象。理論上應該也會輸出100,但問題來了,ASP一直會報錯:
??Microsoft VBScript runtime error '800a01b6'
??Object doesn't support this property or method: 'n.Content'
??用n.Type也會出錯。同樣的程式碼翻譯成PHP,運行卻是可以通過的。為什麼?
??個人分析下來,認為Session可以保存物件是沒錯,只是VBScript中類型轉換的機制太弱,而且沒有明確的強制類型轉換供用戶使用,無法將Session(“node”)正確轉換為ListNode類型。因為是自訂的類,我們只能在每個頁面中都出現類別的定義語句,這樣在ASP看來,每次讀取這個頁面時,ListNode類都是一個新類,所以就不認得Session中的這個類別的物件了。
??結論:盡量不要想到用Session或Application來儲存ASP中自訂類別的物件。如果確實需要,可以考慮用COM來編寫類,然後在VBScript中用:Set Session("obj") = Server.CreateObject("YourApp.YourClass")來建立一個對象,然後即可實現上面預想的功能了。