Solution :
$ sudo chown -R [userid]:staff [git_folder_project]
2012年12月20日 星期四
2012年12月13日 星期四
Mac OSX Zend Studio delimiter / newline setting
General > workspace > New text file line delimiter
-- Unix
General > Editors > Text Editors
-- Insert spaces for tabs
-- Show whitespace characters
Aptana > Editor > CSS > Formatting
Aptana > Editor > HTML > Formatting
Aptana > Editor > Javascript > Formatting
Aptana > Editor > XML > Formatting
Javascript > Code Style > Formatter
PHP > Code Style > Formatter
Web > CSS Files > Code Style > Formatter
Web > HTML Files > Code Style > Formatter
Web > XML Files > Code Style > Formatter
-- Unix
General > Editors > Text Editors
-- Insert spaces for tabs
-- Show whitespace characters
Aptana > Editor > CSS > Formatting
Aptana > Editor > HTML > Formatting
Aptana > Editor > Javascript > Formatting
Aptana > Editor > XML > Formatting
Javascript > Code Style > Formatter
PHP > Code Style > Formatter
Web > CSS Files > Code Style > Formatter
Web > HTML Files > Code Style > Formatter
Web > XML Files > Code Style > Formatter
2012年11月1日 星期四
如何在 Hackathon 中獲勝?Paperclip.io 獲獎的背後祕辛
獲得 T 客邦 授權,將 12 道採訪內容轉貼回來我的部落格。
1、為什麼會選擇開發 Paperclip.io 這樣的服務?你們發現了什麼樣的需求?這個點子是怎麼來的?
我平常在使用 Facebook 時,到不錯的連結或頁面就會順手按讚。但是,按完讚之後過後想找自己前幾天曾按過什麼連結,卻很麻煩。Facebook 一直沒有一個入口介面可以讓你找之前讚過什麼。我認為這件事造成我相當大的困擾,就覺得應該要有一個開發者來寫一個這樣的 App 幫助大家….但很明顯應該是沒有人要寫,於是我就打算自己寫。
剛好 Facebook 舉辦這次比賽,我就打算拿來當這次的題目。
2 、在 Facebook Developer World HACK 2012 裡面,因為每個站都是一天的活動,而且比賽時間只有幾個小時,在這麼短的時間內,你們做了什麼準備,讓作品可以贏得比賽?
選題
首先,我認為是「選題」吧。這是一個「夠小」而且「解決真正大眾困擾」的題目。如果我們選擇進行這個題目。可能題目賣相就會高一點。(我猜)
專注
其次,我認為是「專注」。因為這個「題目」夠小,我們可以把我們的火力集中在於完成核心的實作。主要核心就只是兩隻 API 爬蟲 和網頁爬蟲。這兩個部分很快就寫完了,我們剩下的精力都在調整介面的順暢度。
賣相
第三,調整 demo 時的賣相。因為上台前需要寫投影片和 live demo 自己的作品,demo 只有短短的 5 分鐘,我必須在這麼短的時間內讓評審和其他的參賽者,一目了然知道我們的服務在做什麼,解決了什麼問題。於是我註冊了一個假帳號負責 demo,這裡面的內容是我精選過的,可以看完之後就了解我們在做什麼(我本人 like 過的資料其實很雜亂)。 讓評審能夠一下子理解我們想要作什麼,解決了什麼問題。我想也是拉高勝率的一大原因。
炫技
第四,介面炫技。zhusee 是一個很強的前端工程師,我經常提了一堆的點子,他馬上就能用很炫的方式實作出來。我們嘗試在 demo 前能夠讓所有的介面非常的流暢(即便是等待時間)。另外也花時間做了高難度的首頁特效,吸引目光焦點(畢竟是 Hackathon….當然要炫耀一下)。
3、在整個活動過程中,讓你們印象最深刻的事情是什麼?
參賽的台灣隊伍都很強很有創意。我不知道原來大家會拿 Facebook API 惡搞出這麼多的創意。比如說 Memory Millionaire,我就覺得他們的點子相當有意思。
在宣布三大獎項之後,我們其實一度很失望…一度以為自己落選了。
直到評審宣布評審特別獎,我們發現得獎名單也沒有我們(這也落選會讓我受到很大打擊XD),我們才猜測可能是我們拿到了首獎!!
4、開發 Paperclip.io 總共用了多少時間?在這個過程中,有沒有遇到什麼樣的難關?
其實在比賽之前,我有試寫了一個很小的 prototype,練習 FB API 的存取,但是,成品很糟,存在很多問題。但是因為已經熟了 FB API,我大概覺得這個網站主體架構,在比賽的時限之內,我是有把握可以做完的。
原始設計存在不少問題,用改的拿去比賽太麻煩了。我決定到現場重寫一遍。我們從上午九點到會場,就一直馬不停蹄的在寫 code,寫到開始 demo,所以我也不清楚我們整整寫了多久。
不過中間的確有遇到幾個重大難關:
首先是網頁的爬蟲演算法優先順序問題,當初在設計時,設計的 worker 演算法不好,會造成前面使用者資料沒抓完,後面使用者資料就無法開始進行。這在使用者體驗上會非常不好,因為使用者會覺得網站壞掉了。於是我們花了幾乎整整一個小時打掉原先的 worker 重新設計。
再來是搜尋索引效率的問題,我們嘗試讓這些連結是可用關鍵字被搜尋的,但是資料是分批分批抓進來的,所以會有異步索引的問題。我一直都無法好好的解決這個問題,最後心一橫,不解決了。直接用 MySQL 全文檢索…
不然我們可能會被迫在上台前拿掉這個 feature(但我認為搜尋是一個很大的賣點)。
5、Paperclip.io 隊伍的成員有兩位,你們之間如何分工?
我(xdite)主寫整個網站的架構,設計爬蟲、梳理流程、製作投影片以及上台簡報。zhusee 實作強大的視覺特效以及繪製精美的 UI。我會先把需要加工的頁面在第一時間寫出來,交給 zhusee 操刀設計,我們用 git 控制程式碼,基本上可以做到全速各寫各的,毫不干擾。
6、在 Paperclip.io 的功能裡,有個 Recipes 的分類,讓人很好奇為什麼會特別把食譜做個分類出來?又,書本、食譜這兩個分類的內容,是怎麼去判斷的呢?
在把整個網站初稿寫出來之後,我們認為這個網站如果只有連結實在太單薄了….
於是我們決定加一些分類。分類就是按照 og:type 去分,我們發現有幾個 type 做出來的視覺效果不錯,如:Youtube、食譜、Github …於是我們就決定把這些功能加進去了。
7、在得獎之後,是不是打算升級 Paperclip.io 網站的硬體資源,讓匯入的資料可以更快跑出來?
這個網站吃的資源真的很驚人,我不確定我能不能一直養著它…
說到這個,其實在現場邀請一些朋友幫忙測試時,我們就發現一些效能上的問題了。於是,我們還在當場做了一個非常大的賭注,就是現場刷卡升級 linode 機器(伺服器)。這時候已經快要接近 demo 時間了,要是升級當場出了什麼問題,或者機器來不及當場升級完畢,我們可能就直接開天窗了… 還好這件事並沒有發生。
8、對於想要參加類似 Hack 活動的人,有什麼樣的建議?
我參加過好幾次 Hackathon,得過兩次獎。一次是 2008 年的 Yahoo Open Hack Day(那次是公司同事一起出去比賽,作品是「和多繽紛樂」,得了亞軍)。一次就是 2012 年的這次 Facebook World Hack 得到首獎。
在這好幾次的參賽經驗中,我得到幾個寶貴經驗:
(1) 好的題目很重要
評審希望得獎的題目是 valuable 的。搞笑、諷刺、主題模糊的題目,一定不會得獎。(我在 2009 的比賽跟一群大神等級的朋友合作做了一個精美的搞笑網站「我是專家」,但是…我們沒有得獎)
(2) 賣相非常重要
有些 Hackathon 比賽,甚至投影片比網站重要…。有某幾次的 Hackathon 比賽,竟然是投影片贏了網站。這讓我覺得很不公平也很無奈。但我也理解到比賽要贏就需要賣相的現實。 雖然這次 Hackathon 大會是要求需要提供 source code 以證明不是投影片的實戰比賽,舞弊不至於發生。但我還是認真的投資了快要一個小時在調整假 demo 帳號、截圖、寫投影片…..
9、接下來還會參加其他 Hack 活動的計畫嗎?
暫時沒有。因為我們忘記報名今年的 Yahoo Hack Day 比賽。但我想沒有關係,今年拿到這個獎就值得了…
10、如何把 Bootstrap 改得這麼好看?
我們用了一些網路上的免費素材,比如說
簡單抽換了一下材質,然後用了一點 CSS3 技巧,提升介面質感。這些都是我們平常開發時就相當熟練的技巧,用得很自然。
11、從零到完成作品,用了很短的時間,這是怎麼做到的?有什麼樣的密技?工作進度如何管理?是有什麼樣的開發好習慣嗎?
我想主要是幾個重點:
(1) 時間管理
我參加過很多場 Hackathon。大概知道寫 code 時最容易踢到什麼鐵板。或者開發中最容易遇到什麼鬼打牆的事情。
比賽通常只有短短的幾個小時,所以你要把最浪費時間的部分想辦法節省掉。比如說:如果當天再討論 idea,你的時間就很有可能不夠用。網站需要佈署,佈署需要測試,所以最好有只要一鍵就能 deploy 的環境。domain name 全球生效需要時間,所以 domain name 最好先買。
現場再搞這些事,網站鐵定作不完。何況最後至少要留半小時寫投影片….
(2) 知道什麼該放棄
因為時間不夠,所以其實很多功能,不夠時間讓我們寫到夠完美夠好。於是對自己在開發任何元件時,都要設定 deadline。如果一定時間內(15 min’ 30 min)寫不完,就要放棄,或者是改採其他 solution。
(3) 平常要有自己的 best practices
作網站的時候,我們知道很多工夫都是重複的。比如說作網站一定要有一個網頁主框架、一個 Facebook 登入系統、一個系統管理介面,一些常見的分享功能。
這些事情都小,但是堆起來還是很花時間。如果比賽時,這部分的時間成本若是 0,我們可以把更多的時間花在寫核心功能上。像我上禮拜釋出的一個 app 產生器 Bootstrappers。
這個 Bootstrappers 其實就是我這次比賽時用的大砲,它可以讓你一鍵就產生一個網站雛形,然後馬上開始刻程式。所以當別人還在討論要作什麼時,我這部分已經作完了….
而我和夥伴已經一起工作將近三個月,彼此有不錯的默契。我們在寫 code 時,了解彼此寫 code 的習慣,於是接力對方的部分,速度就非常快。而我們更用了 git 這套程式碼版本控制系統,可以做到各寫各的,不會干擾。
12、如果 Facebook 邀請你們加入當員工,會進去嗎?
會慎重考慮。
reference : http://blog.xdite.net/posts/2012/10/20/how-to-win-hackthon/
2012年10月31日 星期三
Reading a Remote File Using PHP
To read a remote file from php you have at least four options :
1. Use fopen()
2. Use file_get_contents()
3. CURL
4. Make your own function using php's socket functions.
2. Use file_get_contents()
3. CURL
4. Make your own function using php's socket functions.
First i need to warn you about something. You can only use fopen() and file_get_contents() when fopen wrappers is enabled. This parameter is specified in the php.ini file and cannot be changed at run time usingini_set(), To know whether you can use these two or not you can use the following code to check the value of fopen wrapper seting.
if (ini_get('allow_url_fopen') == '1') {
// use fopen() or file_get_contents()
} else {
// use curl or your custom function
}
// use fopen() or file_get_contents()
} else {
// use curl or your custom function
}
1 . Using fopen()
If you use fopen() to read a remote file the process is as simple as reading from a local file. The only difference is that you will specify the URL instead of the file name. Take a look at the example below :
// make sure the remote file is successfully opened before doing anything else
if ($fp = fopen('http://www.google.com/', 'r')) {
$content = '';
// keep reading until there's nothing left
while ($line = fread($fp, 1024)) {
$content .= $line;
}
// do something with the content here
// ...
} else {
// an error occured when trying to open the specified url
}
if ($fp = fopen('http://www.google.com/', 'r')) {
$content = '';
// keep reading until there's nothing left
while ($line = fread($fp, 1024)) {
$content .= $line;
}
// do something with the content here
// ...
} else {
// an error occured when trying to open the specified url
}
Now, the code above use fread() function in the while loop to read up to 1024 bytes of data in a single loop. That code can also be written like this :
// make sure the remote file is successfully opened before doing anything else
if ($fp = fopen('http://www.google.com/', 'r')) {
$content = '';
// keep reading until there's nothing left
while ($line = fgets($fp, 1024)) {
$content .= $line;
}
// do something with the content here
// ...
} else {
// an error occured when trying to open the specified url
}
if ($fp = fopen('http://www.google.com/', 'r')) {
$content = '';
// keep reading until there's nothing left
while ($line = fgets($fp, 1024)) {
$content .= $line;
}
// do something with the content here
// ...
} else {
// an error occured when trying to open the specified url
}
instead of fread() we use fgets() which reads one line of data up to 1024 bytes. The first code is much more preferable than the second though. Just imagine if the remote file's size is 50 kilobytes and consists of 300 lines. Using the first code will cause the loop to be executed about fifty times but using the second the loop will be executed three hundred times.
If you consider the cost to call a function plus the time required to make 300 requests compared to just 5 then clearly the first one is the winner.
2. Using file_get_contents()
This is my favorite way of reading a remote file because it is very simple. Just call this function and specify a url as the parameter. But make sure you remember to check the return value first to determine if it return an error before processing the result
$content = file_get_contents('http://www.google.com/');
if ($content !== false) {
// do something with the content
} else {
// an error happened
}
if ($content !== false) {
// do something with the content
} else {
// an error happened
}
3. CURL
Unlike the two methods above using CURL cannot be said as straigthforward. Although this library is very useful to connect and communicate with may different protocols ( not just http ) it requires more effort to learn. And another problem is that not all web host have this library in their php installation. So we better make sure to check if the library is installed before trying to use it.
Here is a basic example on fetching a remote file
// make sure curl is installed
if (function_exists('curl_init')) {
// initialize a new curl resource
$ch = curl_init();
// set the url to fetch
curl_setopt($ch, CURLOPT_URL, 'http://www.google.com');
// don't give me the headers just the content
curl_setopt($ch, CURLOPT_HEADER, 0);
// return the value instead of printing the response to browser
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// use a user agent to mimic a browser
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
$content = curl_exec($ch);
// remember to always close the session and free all resources
curl_close($ch);
} else {
// curl library is not installed so we better use something else
}
if (function_exists('curl_init')) {
// initialize a new curl resource
$ch = curl_init();
// set the url to fetch
curl_setopt($ch, CURLOPT_URL, 'http://www.google.com');
// don't give me the headers just the content
curl_setopt($ch, CURLOPT_HEADER, 0);
// return the value instead of printing the response to browser
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// use a user agent to mimic a browser
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
$content = curl_exec($ch);
// remember to always close the session and free all resources
curl_close($ch);
} else {
// curl library is not installed so we better use something else
}
In some cases using CURL is faster than using file_get_contents() or fopen(). This is because CURL handles compression protocols by default ( for example gzip ). Many sites, big and small, use gzip compression to compress their web pages in order to save bandwidth. This site, for example, also use gzip compression which cut the bandwidth used into half. So if you're the type who just can't wait CURL will fit you most.
4. Custom functions
In the worst case your server will have fopen wrappers disabled and don't have CURL library installed. In this sad situation you just have to make your own way.
Our function shall be named getRemoteFile() which takes only one parameter, the url for the remote file. The skeleton for this function is shown below
function getRemoteFile($url)
{
// 1. get the host name and url path
// 2. connect to the remote server
// 3. send the necessary headers to get the file
// 4. retrieve the response from the remote server
// 5. strip the headers
// 6. return the file content
}
{
// 1. get the host name and url path
// 2. connect to the remote server
// 3. send the necessary headers to get the file
// 4. retrieve the response from the remote server
// 5. strip the headers
// 6. return the file content
}
To extract the host name and url path from the given url we'll use parse_url() function. When given a url this function will spit out the followings :
- scheme
- host
- port
- user
- pass
- path
- query
- fragment
For example, if the url is http://www.php-mysql-tutorial.com/somepage.php then parse_url() will return :
Array ( [scheme] => http [host] => www.php-mysql-tutorial.com [path] => /somepage.php )
and if the url is http://myusername:mypassword@www.php-mysql-tutorial.com/somepage.php?q=whatsthis#ouch then parse_url() will return this :
Array ( [scheme] => http [host] => www.php-mysql-tutorial.com [user] => myusername [pass] => mypassword [path] => /somepage.php [query] => q=whatsthis [fragment] => ouch )
For our new function we only care about the host, port, path and query.
To establish a connection to a remote server we use fsockopen(). This function requires five arguments, the hostname, port number, a reference for error number, a reference for the error message and timeout
function getRemoteFile($url)
{
// get the host name and url path
$parsedUrl = parse_url($url);
$host = $parsedUrl['host'];
if (isset($parsedUrl['path'])) {
$path = $parsedUrl['path'];
} else {
// the url is pointing to the host like http://www.mysite.com
$path = '/';
}
if (isset($parsedUrl['query'])) {
$path .= '?' . $parsedUrl['query'];
}
if (isset($parsedUrl['port'])) {
$port = $parsedUrl['port'];
} else {
// most sites use port 80
$port = '80';
}
$timeout = 10;
$response = ''; // connect to the remote server
$fp = @fsockopen($host, '80', $errno, $errstr, $timeout );
if( !$fp ) {
echo "Cannot retrieve $url";
} else {
// send the necessary headers to get the file
fputs($fp, "GET $path HTTP/1.0\r\n" .
"Host: $host\r\n" .
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3\r\n" .
"Accept: */*\r\n" .
"Accept-Language: en-us,en;q=0.5\r\n" .
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" .
"Keep-Alive: 300\r\n" .
"Connection: keep-alive\r\n" .
"Referer: http://$host\r\n\r\n");
// retrieve the response from the remote server
while ( $line = fread( $fp, 4096 ) ) {
$response .= $line;
}
fclose( $fp );
// strip the headers
$pos = strpos($response, "\r\n\r\n");
$response = substr($response, $pos + 4);
}
// return the file content
return $response;
}
{
// get the host name and url path
$parsedUrl = parse_url($url);
$host = $parsedUrl['host'];
if (isset($parsedUrl['path'])) {
$path = $parsedUrl['path'];
} else {
// the url is pointing to the host like http://www.mysite.com
$path = '/';
}
if (isset($parsedUrl['query'])) {
$path .= '?' . $parsedUrl['query'];
}
if (isset($parsedUrl['port'])) {
$port = $parsedUrl['port'];
} else {
// most sites use port 80
$port = '80';
}
$timeout = 10;
$response = ''; // connect to the remote server
$fp = @fsockopen($host, '80', $errno, $errstr, $timeout );
if( !$fp ) {
echo "Cannot retrieve $url";
} else {
// send the necessary headers to get the file
fputs($fp, "GET $path HTTP/1.0\r\n" .
"Host: $host\r\n" .
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3\r\n" .
"Accept: */*\r\n" .
"Accept-Language: en-us,en;q=0.5\r\n" .
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" .
"Keep-Alive: 300\r\n" .
"Connection: keep-alive\r\n" .
"Referer: http://$host\r\n\r\n");
// retrieve the response from the remote server
while ( $line = fread( $fp, 4096 ) ) {
$response .= $line;
}
fclose( $fp );
// strip the headers
$pos = strpos($response, "\r\n\r\n");
$response = substr($response, $pos + 4);
}
// return the file content
return $response;
}
The code above sends nine lines of headers but only the first two is mandatory. So even if you send only these
fputs($fp, "GET $path HTTP/1.0\r\n" .
"Host: $host\r\n\r\n");
"Host: $host\r\n\r\n");
the function will likely be working correctly. Not always though. Since the file is stored in a remote server It really up to that server to reply to your request or not. Some people code their page to block any request without the proper referer header. Some will only accept a specific user agent. Other will require cookies set in the header.
If you want to see what headers should be sent to successfully fetch a specific remote file try using firefoxplus live http headers plugin. It's really a useful little tool
reference : http://www.php-mysql-tutorial.com/wikis/php-tutorial/reading-a-remote-file-using-php.aspx
2012年10月10日 星期三
facebook fbml login-button not working with perms
2012年8月20日 星期一
Using FastCGI to Host PHP Applications on IIS 6.0
Introduction
This article explains how to use the Microsoft IIS FastCGI extension to set up and run PHP applications on Windows XP and Windows Server® 2003 operating systems.
What is FastCGI?
FastCGI is a standard protocol that allows the CGI executable files for application frameworks to interface with the Web server. It differs from the standard CGI protocol in that FastCGI reuses CGI processes for multiple requests, which provides a significant performance boost as compared to CGI. Support for IIS FastCGI enables IIS to host normal CGI programs like PHP or Ruby on Rails by using the FastCGI protocol, and to offer high performance and stability for production deployment of such application frameworks.
Using the IIS FastCGI support includes the following:
IIS Web server
IIS FastCGI extension
CGI program (such as php-cgi.exe)
The Web server dispatches HTTP requests to your application to the FastCGI component, which in turn launches the CGI program executable, and forwards the request for processing. Once the request is finished and the response is returned back to the server and sent to the client, the CGI process is reused for a subsequent request. This helps to avoid the high performance penalty of starting a new process for each request, which results in better performance and scalability in a production environment.
To learn more about the FastCGI protocol, see http://www.fastcgi.com/devkit/doc/fcgi-spec.html.
Install the FastCGI Extension for IIS 6.0 and IIS 5.1
You can download the FastCGI extension for 32-bit and 64-bit Windows XP and Windows Server 2003 here:
http://www.iis.net/extensions/fastcgi
When you run the FastCGI installer, it copies FastCGI-specific files to the "%windir%\system32\inetsrv" folder, and then registers and enables the FastCGI Web server extension. Of the files that the installer copies, note the following:
fcgiext.dll – This is the actual FastCGI handler that communicates with FastCGI-enabled processes for processing requests.
fcgiext.ini – This is the configuration file that contains the mapping of file extensions to FastCGI processes. It also contains the configuration of FastCGI process pools.
fcgiconfig.js – This configures the FastCGI extension. The script updates the fcgiext.ini file, modifies the IIS metabase and recycles the Web service application pools if necessary.
Download and Install PHP
The FastCGI extension is fully compatible with the current official PHP 4.4.x and PHP 5.x distribution for Windows, available from http://windows.php.net/download. Since the FastCGI extension hosts and executes php processes in a single threaded manner, it is recommended that you download and install the non-thread-safe PHP build that is available for Windows. The non-thread-safe PHP build provides a performance boost from a lack of thread safety that is acceptable for a single-concurrency environment like FastCGI.
Configure the FastCGI Extension to Work with PHP
Once PHP is installed on Windows, you have two options to configure FastCGI: use the configuration script that is provided with the installation of the FastCGI extension, or perform all the configuration tasks manually by modifying IIS configuration settings and the fcgiext.ini file.
Configure the FastCGI Extension to Work with PHP by Using the Configuration Script
The configuration script with the name fcgconfig.js is provided with the installation of the FastCGI extension. It is located in %windir%\system32\inetsrv.
To configure the FastCGI extension to work with PHP:
Open a command prompt.
Change the current directory to %windir%\system32\inetsrv.
Register the PHP CGI program as the one that will be processing .php extensions by running the following configuration script:
cscript fcgiconfig.js -add -section:"PHP" -extension:php -path:"C:\PHP\php-cgi.exe"
Replace C:\PHP\php-cgi.exe with the path to php-cgi.exe if you installed to a directory other than C:\PHP.
Note: If you do not want to register the PHP extension to be processed by the FastCGI component on your entire server, and only want to register it for a specific Web site, add a "–site:[siteId]" argument, for example:
cscript fcgiconfig.js -add -section:"PHP" -extension:php -path:"C:\PHP\php-cgi.exe" –site:1
Note: For a complete list of configuration parameters that are supported by the FastCGI extension, see the FastCGI extension documentation.
Manually Configure the FastCGI Extension to Work with PHP
To manually configure the IIS and FastCGI extension, you must create script mappings for the PHP extension in the IIS metabase, and modify the fcgiext.ini file that is located in %windir%\system32\inetsrv.
To create script mapping:
Launch inetmgr.exe.
Double-click the machine icon for the local computer.
Right-click Web Sites and click Properties.
Click the Home Directory tab.
Click the Configuration… button.
Click the Add… button.
In the Add/Edit Application Extension Mapping dialog box, click Browse.... Navigate to the fcgiext.dll file that is located in %windir%\system32\inetsrv.
Note: If you need to use FastCGI in 32-bit mode on a 64-bit machine, navigate to %windir%\SysWOW64\inetsrv.
8. In the Extension text box, enter .php.
9. Under Verbs, in the Limit to text box, enter GET,HEAD,POST.
10. Ensure that the Script engine and Verify that file exists check boxes are selected.
11. Click OK.
To modify the fcigext.ini file:
Once the script mapping has been added, modify the fcgiext.ini file.
Add an extension to application mapping (php=PHP) to the [Types] section.
Add a [PHP] section with ExePath=c:\php\php-cgi.exe (assuming you installed PHP files to the C:\PHP folder).
[Types]
…
php=PHP
…
[PHP]
ExePath=c:\php\php-cgi.exe
3. After you save the changes to the fcgiext.ini file, restart the application pool that is associated with the Web site that hosts your PHP applications.
To configure a default document in IIS:
Most PHP applications use a file named index.php as the default application document. Configure IIS to treat this file as the default content page.
Launch inetmgr.exe.
Double-click the machine icon for the local computer.
Right-click Web Sites and click Properties.
Click the Documents tab.
Click the Add… button.
In the Add Content Page dialog box, in the Default content page text box, enter index.php.
Click OK.
Set the FastCGI Configuration for Optimal Functionality, Security, and Performance with PHP
IIS focuses on full PHP functionality support and performance of PHP applications that are running on the FastCGI extension. In collaboration with Zend Technologies, IIS identified the set of configuration settings for the FastCGI extension and PHP that would provide optimal functionality and performance for PHP applications when running on Windows by using the FastCGI extension.
To obtain optimal functionality and performance, configure your server as follows:
1. Modify the php.ini file as follows:
Set fastcgi.impersonate = 1. FastCGI under IIS supports the ability to impersonate the security tokens of the calling client. This allows IIS to define the security context under which the request runs.
Set cgi.fix_pathinfo=1. cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. Previously, PHP behavior was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not define PATH_INFO. For more information about PATH_INFO, see the cgi specifications. Setting this value to 1 will cause PHP CGI to fix its paths to conform to the specification.
Set cgi.force_redirect = 0.
2. Set the FastCGI configuration settings for the PHP section by running fcgiconfig.js as follows:
Set the FastCGI process pool property InstanceMaxRequests to 10000. This setting specifies that the FastCGI extension will recycle php-cgi.exe after it has processed 10000 requests successfully.
> cscript fcgiconfig.js -set -section:"PHP" -InstanceMaxRequests:10000
3. Configure the FastCGI extension to set the PHP_FCGI_MAX_REQUESTS environment variables for the PHP process to 10000.This setting instructs php-cgi.exe to recycle itself after it has processed 10000 requests successfully.
> cscript fcgiconfig.js -set -section:"PHP" -EnvironmentVars:PHP_FCGI_MAX_REQUESTS:10000
Note: You can configure InstanceMaxRequests and PHP_FCGI_MAX_REQUESTS to use numbers other than 10000. As a general rule, ensure that the value of InstanceMaxRequests is less than or equal to the value of PHP_FCGI_MAX_REQUESTS.
Test PHP CGI
After installing the FastCGI extension and registering and configuring the PHP CGI, you can request your PHP application and use it normally.
To test the PHP application, create and request a phpinfo.php page in your site that contains the following:
You should see something like the following:
Note that the Server API field indicates that PHP is hosted in FastCGI mode.
reference : http://learn.iis.net/page.aspx/247/using-fastcgi-to-host-php-applications-on-iis-60/
2012年6月26日 星期二
PHP Using two class with the same name (Duplicate class name)
$v15_txt=file_get_contents($old_dir.'/libraries/joomla/version.php');
$v15_txt=preg_replace('/class JVersion/i', 'class JVersion15', $v15_txt);
eval('?>'.$v15_txt);
$jvold=new JVersion15;
$old_version = $jvold->RELEASE.'.'.$jvold->DEV_LEVEL;
$v25_txt=file_get_contents($new_dir.'/libraries/cms/version/version.php');
$v25_txt=preg_replace('/class JVersion/i', 'class JVersion25', $v25_txt);
eval('?>'.$v25_txt);
$jvnew=new JVersion25;
$new_version = $jvnew->RELEASE.'.'.$jvnew->DEV_LEVEL;
Essential JavaScript Namespacing Patterns
In this post, I'll be discussing both intermediate and advanced patterns and approaches for namespacing in JavaScript. We're going to begin with the latter as I believe many of my readers have some prior experience in this area. If however you're new to namespacing with the language and would like to learn more about some of the fundamentals, please feel free to skip to the section titled 'namespacing fundamentals' to continue reading.
What is namespacing?
In many programming languages, namespacing is a technique employed to avoid collisions with other objects or variables in the global namespace. They're also extremely useful for helping organize blocks of functionality in your application into easily manageable groups that can be uniquely identified.
In JavaScript, namespacing at an enterprise level is critical as it's important to safeguard your code from breaking in the event of another script on the page using the same variable or method names as you are. With the number of third-party tags regularly injected into pages these days, this can be a common problem we all need to tackle at some point in our careers. As a well-behaved 'citizen' of the global namespace, it's also imperative that you do your best to similarly not prevent other developer's scripts executing due to the same issues.
Whilst JavaScript doesn't really have built-in support for namespaces like other languages, it does have objects and closures which can be used to achieve a similar effect.
Advanced namespacing patterns
In this section, I'll be exploring some advanced patterns and utility techniques that have helped me when working on larger projects requiring a re-think of how application namespacing is approached. I should state that I'm not advocating any of these as *the* way to do things, but rather just ways that I've found work in practice.
Automating nested namespacing
As you're probably aware, a nested namespace provides an organized hierarchy of structures in an application and an example of such a namespace could be the following:application.utilities.drawing.canvas.2d. In JavaScript the equivalent of this definition using the object literal pattern would be:
- var application = {
- utilities:{
- drawing:{
- canvas:{
- 2d:{
- /*...*/
- }
- }
- }
- }
- };
Wow, that's ugly.
One of the obvious challenges with this pattern is that each additional depth you wish to create requires yet another object to be defined as a child of some parent in your top-level namespace. This can become particularly laborious when multiple depths are required as your application increases in complexity.
How can this problem be better solved? In JavaScript Patterns,Stoyan Stefanov presents a very-clever approach for automatically defining nested namespaces under an existing global variable using a convenience method that takes a single string argument for a nest, parses this and automatically populates your base namespace with the objects required.
The method he suggests using is the following, which I've updated it to be a generic function for easier re-use with multiple namespaces:
- // top-level namespace being assigned an object literal
- var myApp = myApp || {};
- // a convenience function for parsing string namespaces and
- // automatically generating nested namespaces
- function extend( ns, ns_string ) {
- var parts = ns_string.split('.'),
- parent = ns,
- pl, i;
- if (parts[0] == "myApp") {
- parts = parts.slice(1);
- }
- pl = parts.length;
- for (i = 0; i < pl; i++) {
- //create a property if it doesnt exist
- if (typeof parent[parts[i]] == 'undefined') {
- parent[parts[i]] = {};
- }
- parent = parent[parts[i]];
- }
- return parent;
- }
- // sample usage:
- // extend myApp with a deeply nested namespace
- var mod = extend(myApp, 'myApp.modules.module2');
- // the correct object with nested depths is output
- console.log(mod);
- // minor test to check the instance of mod can also
- // be used outside of the myApp namesapce as a clone
- // that includes the extensions
- console.log(mod == myApp.modules.module2); //true
- // further demonstration of easier nested namespace
- // assignment using extend
- extend(myApp, 'moduleA.moduleB.moduleC.moduleD');
- extend(myApp, 'longer.version.looks.like.this');
- console.log(myApp);
Web inspector output:
Note how where one would previously have had to explicitly declare the various nests for their namespace as objects, this can now be easily achieved using a single, cleaner line of code. This works exceedingly well when defining purely namespaces alone, but can seem a little less flexible when you want to define both functions and properties at the same time as declaring your namespaces. Regardless, it is still incredibly powerful and I regularly use a similar approach in some of my projects.
Dependency declaration pattern
In this section we're going to take a look at a minor augmentation to the nested namespacing pattern you may be used to seeing in some applications. We all know that local references to objects can decrease overall lookup times, but let's apply this to namespacing to see how it might look in practice:
- // common approach to accessing nested namespaces
- myApp.utilities.math.fibonacci(25);
- myApp.utilities.math.sin(56);
- myApp.utilities.drawing.plot(98,50,60);
- // with local/cached references
- Var utils = myApp.utilities,
- maths = utils.math,
- drawing = utils.drawing;
- // easier to access the namespace
- maths.fibonacci(25);
- maths.sin(56);
- drawing.plot(98, 50,60);
- // note that the above is particularly performant when
- // compared to hundreds or thousands of calls to nested
- // namespaces vs. a local reference to the namespace
Working with a local variable here is almost always faster than working with a top-level global (eg.myApp). It's also both more convenient and more performant than accessing nested properties/sub-namespaces on every subsequent line and can improve readability in more complex applications.
Stoyan recommends declaring localized namespaces required by a function or module at the top of your function scope (using the single-variable pattern) and calls this a dependancy declaration pattern. One if the benefits this offers is a decrease in locating dependencies and resolving them, should you have an extendable architecture that dynamically loads modules into your namespace when required.
In my opinion this pattern works best when working at a modular level, localizing a namespace to be used by a group of methods. Localizing namespaces on a per-function level, especially where there is significant overlap between namespace dependencies would be something I would recommend avoiding where possible. Instead, define it further up and just have them all access the same reference.
Deep object extension
An alternative approach to automatic namespacing is deep object extension. Namespaces defined using object literal notation may be easily extended (or merged) with other objects (or namespaces) such that the properties and functions of both namespaces can be accessible under the same namespace post-merge.
This is something that's been made fairly easy to accomplish with modern JavaScript frameworks (eg. see jQuery's $.extend), however, if you're looking to extend object (namespaces) using vanilla JS, the following routine may be of assistance.
- // extend.js
- // written by andrew dupont, optimized by addy osmani
- function extend(destination, source) {
- var toString = Object.prototype.toString,
- objTest = toString.call({});
- for (var property in source) {
- if (source[property] && objTest == toString.call(source[property])) {
- destination[property] = destination[property] || {};
- extend(destination[property], source[property]);
- } else {
- destination[property] = source[property];
- }
- }
- return destination;
- };
- console.group("objExtend namespacing tests");
- // define a top-level namespace for usage
- var myNS = myNS || {};
- // 1. extend namespace with a 'utils' object
- extend(myNS, {
- utils:{
- }
- });
- console.log('test 1', myNS);
- //myNS.utils now exists
- // 2. extend with multiple depths (namespace.hello.world.wave)
- extend(myNS, {
- hello:{
- world:{
- wave:{
- test: function(){
- /*...*/
- }
- }
- }
- }
- });
- // test direct assignment works as expected
- myNS.hello.test1 = 'this is a test';
- myNS.hello.world.test2 = 'this is another test';
- console.log('test 2', myNS);
- // 3. what if myNS already contains the namespace being added
- // (eg. 'library')? we want to ensure no namespaces are being
- // overwritten during extension
- myNS.library = {
- foo:function(){}
- };
- extend(myNS, {
- library:{
- bar:function(){
- /*...*/
- }
- }
- });
- // confirmed that extend is operating safely (as expected)
- // myNS now also contains library.foo, library.bar
- console.log('test 3', myNS);
- // 4. what if we wanted easier access to a specific namespace without having
- // to type the whole namespace out each time?.
- var shorterAccess1 = myNS.hello.world;
- shorterAccess1.test3 = "hello again";
- console.log('test 4', myNS);
- //success, myApp.hello.world.test3 is now 'hello again'
- console.groupEnd();
If you do happen to be using jQuery in your application, you can achieve the exact same object namespact extensibility using $.extend as seen below:
- // top-level namespace
- var myApp = myApp || {};
- // directly assign a nested namespace
- myApp.library = {
- foo:function(){ /*..*/}
- };
- // deep extend/merge this namespace with another
- // to make things interesting, let's say it's a namespace
- // with the same name but with a different function
- // signature: $.extend(deep, target, object1, object2)
- $.extend(true, myApp, {
- library:{
- bar:function(){
- /*..*/
- }
- }
- });
- console.log('test', myApp);
- // myApp now contains both library.foo() and library.bar() methods
- // nothing has been overwritten which is what we're hoping for.
For the sake of thoroughness, please see here for jQuery $.extend equivalents to the rest of the namespacing experiments found in this section.
Namespacing Fundamentals
Namespaces can be found in almost any serious JavaScript application. Unless you're working with a code-snippet, it's imperative that you do your best to ensure that you're implementing namespacing correctly as it's not just simple to pick-up, it'll also avoid third party code clobbering your own. The patterns we'll be examining in this section are:
- Single global variables
- Object literal notation
- Nested namespacing
- Immediately-invoked Function Expressions
- Namespace injection
1.Single global variables
One popular pattern for namespacing in JavaScript is opting for a single global variable as your primary object of reference. A skeleton implementation of this where we return an object with functions and properties can be found below:
- var myApplication = (function(){
- function(){
- /*...*/
- },
- return{
- /*...*/
- }
- })();
Although this works for certain situations, the biggest challenge with the single global variable pattern is ensuring that no one else has used the same global variable name as you have in the page.
One solution to this problem, as mentioned by Peter Michaux, is to use prefix namespacing. It's a simple concept at heart, but the idea is you select a unique prefix namespace you wish to use (in this example, "myApplication_") and then define any methods, variables or other objects after the prefix as follows:
- var myApplication_propertyA = {};
- var myApplication_propertyB = {};
- funcion myApplication_myMethod(){ /*..*/ }
This is effective from the perspective of trying to lower the chances of a particular variable existing in the global scope, but remember that a uniquely named object can have the same effect. This aside, the biggest issue with the pattern is that it can result in a large number of global objects once your application starts to grow. There is also quite a heavy reliance on your prefix not being used by any other developers in the global namespace, so be careful if opting to use this.
For more on Peter's views about the single global variable pattern, read his excellent post on them here.
2. Object literal notation
Object literal notation can be thought of as an object containing a collection of key:value pairs with a colon separating each pair of keys and values. It's syntax requires a comma to be used after each key:value pair with the exception of the last item in your object, similar to a normal array.
- var myApplication = {
- getInfo:function(){ /**/ },
- // we can also populate our object literal to support
- // further object literal namespaces containing anything
- // really:
- models : {},
- views : {
- pages : {}
- },
- collections : {}
- };
One can also opt for adding properties directly to the namespace:
- myApplication.foo = function(){
- return "bar";
- }
- myApplication.utils = {
- toString:function(){
- /*..*/
- },
- export: function(){
- /*..*/
- }
- }
Object literals have the advantage of not polluting the global namespace but assist in organizing code and parameters logically. They're beneficial if you wish to create easily-readable structures that can be expanded to support deep nesting. Unlike simple global variables, object literals often also take into account tests for the existence of a variable by the same name so the chances of collision occurring are significantly reduced.
The code at the very top of the next sample demonstrates the different ways in which you can check to see if a variable (object namespace) already exists before defining it. You'll commonly see developers using Option 1, however Options 3 and 5 may be considered more thorough and Option 4 is considered a good best-practice.
- // This doesn't check for existence of 'myApplication' in
- // the global namespace. Bad practice as you can easily
- // clobber an existing variable/namespace with the same name
- var myApplication = {};
- /*
- The following options *do* check for variable/namespace existence.
- If already defined, we use that instance, otherwise we assign a new
- object literal to myApplication.
- Option 1: var myApplication = myApplication || {};
- Option 2 if(!MyApplication) MyApplication = {};
- Option 3: var myApplication = myApplication = myApplication || {}
- Option 4: myApplication || (myApplication = {});
- Option 5: var myApplication = myApplication === undefined ? {} : myApplication;
- */
There is of course a huge amount of variance in how and where object literals are used for organizing and structuring code. For smaller applications wishing to expose a nested API for a particular self-enclosed module, you may just find yourself using this next pattern when returning an interface for other developers to use. It's a variation on the module pattern where the core structure of the pattern is an IIFE, however the returned interface is an object literal:
- var namespace = (function () {
- // defined within the local scope
- var privateMethod1 = function () { /* ... */ }
- var privateMethod2 = function () { /* ... */ }
- var privateProperty1 = 'foobar';
- return {
- // the object literal returned here can have as many
- // nested depths as you wish, however as mentioned,
- // this way of doing things works best for smaller,
- // limited-scope applications in my personal opinion
- publicMethod1: privateMethod1,
- //nested namespace with public properties
- properties:{
- publicProperty1: privateProperty1
- },
- //another tested namespace
- utils:{
- publicMethod2: privateMethod2
- }
- ...
- }
- })();
The benefit of object literals is that they offer us a very elegant key/value syntax to work with; one where we're able to easily encapsulate any distinct logic or functionality for our application in a way that clearly separates it from others and provides a solid foundation for extending your code.
A possible downside however is that object literals have the potential to grow into long syntactic constructs. Opting to take advantage of the nested namespace pattern (which also uses the same pattern as it's base)
This pattern has a number of other useful applications too. In addition to namespacing, it's often of benefit to decouple the default configuration for your application into a single area that can be easily modified without the need to search through your entire codebase just to alter them – object literals work great for this purpose. Here's an example of a hypothetical object literal for configuration:
- var myConfig = {
- language: 'english',
- defaults: {
- enableGeolocation: true,
- enableSharing: false,
- maxPhotos: 20
- },
- theme: {
- skin: 'a',
- toolbars: {
- index: 'ui-navigation-toolbar',
- pages: 'ui-custom-toolbar'
- }
- }
- }
Note that there are really only minor syntactical differences between the object literal pattern and a standard JSON data set. If for any reason you wish to use JSON for storing your configurations instead (e.g. for simpler storage when sending to the back-end), feel free to. For more on the object literal pattern, I recommend reading Rebecca Murphey's excellent article on the topic.
3. Nested namespacing
An extension of the object literal pattern is nested namespacing. It's another common pattern used that offers a lower risk of collision due to the fact that even if a namespace already exists, it's unlikely the same nested children do.
Does this look familiar?
- YAHOO.util.Dom.getElementsByClassName('test');
Yahoo's YUI framework uses the nested object namespacing pattern regularly and at AOL we also use this pattern in many of our main applications. A sample implementation of nested namespacing may look like this:
- var myApp = myApp || {};
- // perform a similar existence check when defining nested
- // children
- myApp.routers = myApp.routers || {};
- myApp.model = myApp.model || {};
- myApp.model.special = myApp.model.special || {};
- // nested namespaces can be as complex as required:
- // myApp.utilities.charting.html5.plotGraph(/*..*/);
- // myApp.modules.financePlanner.getSummary();
- // myApp.services.social.facebook.realtimeStream.getLatest();
You can also opt to declare new nested namespaces/properties as indexed properties as follows:
- myApp["routers"] = myApp["routers"] || {};
- myApp["models"] = myApp["models"] || {};
- myApp["controllers"] = myApp["controllers"] || {};
Both options are readable, organized and offer a relatively safe way of namespacing your application in a similar fashion to what you may be used to in other languages. The only real caveat however is that it requires your browser's JavaScript engine first locating the myApp object and then digging down until it gets to the function you actually wish to use.
This can mean an increased amount of work to perform lookups, however developers such as Juriy Zaytsev have previously tested and found the performance differences between single object namespacing vs the 'nested' approach to be quite negligible.
4. Immediately-invoked Function Expressions (IIFE)s
An IIFE is effectively an unnamed function which is immediately invoked after it's been defined. In JavaScript, because both variables and functions explicitly defined within such a context may only be accessed inside of it, function invocation provides an easy means to achieving privacy.
This is one of the many reasons why IIFEs are a popular approach to encapsulating application logic to protect it from the global namespace. You've probably come across this pattern before under the name of a self-executing (or self-invoked) anonymous function, however I personally prefer Ben Alman's naming convection for this particular pattern as I believe it to be both more descriptive and more accurate.
The simplest version of an IIFE could be the following:
- // an (anonymous) immediately-invoked function expression
- (function(){ /*...*/})();
- // a named immediately-invoked function expression
- (function foobar(){ /*..*/}());
- // this is technically a self-executing function which is quite different
- function foobar(){ foobar(); }
whilst a slightly more expanded version of the first example might look like:
- var namespace = namespace || {};
- // here a namespace object is passed as a function
- // parameter, where we assign public methods and
- // properties to it
- (function( o ){
- o.foo = "foo";
- o.bar = function(){
- return "bar";
- };
- })(namespace);
- console.log(namespace);
Whilst readable, this example could be significantly expanded on to address common development concerns such as defined levels of privacy (public/private functions and variables) as well as convenient namespace extension. Let's go through some more code:
- // namespace (our namespace name) and undefined are passed here
- // to ensure 1. namespace can be modified locally and isn't
- // overwritten outside of our function context
- // 2. the value of undefined is guaranteed as being truly
- // undefined. This is to avoid issues with undefined being
- // mutable pre-ES5.
- ;(function ( namespace, undefined ) {
- // private properties
- var foo = "foo",
- bar = "bar";
- // public methods and properties
- namespace.foobar = "foobar";
- namespace.sayHello = function () {
- speak("hello world");
- };
- // private method
- function speak(msg) {
- console.log("You said: " + msg);
- };
- // check to evaluate whether 'namespace' exists in the
- // global namespace - if not, assign window.namespace an
- // object literal
- }(window.namespace = window.namespace || {});
- // we can then test our properties and methods as follows
- // public
- console.log(namespace.foobar); // foobar
- namescpace.sayHello(); // hello world
- // assigning new properties
- namespace.foobar2 = "foobar";
- console.log(namespace.foobar2);
Extensibility is of course key to any scalable namespacing pattern and IIFEs can be used to achieve this quite easily. In the below example, our 'namespace' is once again passed as an argument to our anonymous function and is then extended (or decorated) with further functionality:
- // let's extend the namespace with new functionality
- (function( namespace, undefined ){
- // public method
- namespace.sayGoodbye = function(){
- console.log(namespace.foo);
- console.log(namespace.bar);
- speak('goodbye');
- }
- }( window.namespace = window.namespace || {});
namespace.sayGoodbye(); //goodbye
That's it for IIFEs for the time-being. If you would like to find out more about this pattern, I recommend reading both Ben's IIFE post and Elijah Manor's post on namespace patterns from C#.
5. Namespace injection
Namespace injection is another variation on the IIFE where we 'inject' the methods and properties for a specific namespace from within a function wrapper using this as a namespace proxy. The benefit this pattern offers is easy application of functional behaviour to multiple objects or namespaces and can come in useful when applying a set of base methods to be built on later (eg. getters and setters).
The disadvantages of this pattern are that there may be easier or more optimal approaches to achieving this goal (eg. deep object extension / merging) which I cover earlier in the article..
Below we can see an example of this pattern in action, where we use it to populate the behaviour for two namespaces: one initially defined (utils) and another which we dynamically create as a part of the functionality assignment for utils (a new namespace called tools).
- var myApp = myApp || {};
- myApp.utils = {};
- (function() {
- var val = 5;
- this.getValue = function() {
- return val;
- };
- this.setValue = function(newVal) {
- val = newVal;
- }
- // also introduce a new sub-namespace
- this.tools = {};
- }).apply(myApp.utils);
- // inject new behaviour into the tools namespace
- // which we defined via the utilities module
- (function(){
- this.diagnose = function(){
- return 'diagnosis';
- }
- }).apply(myApp.utils.tools);
- // note, this same approach to extension could be applied
- // to a regular IIFE, by just passing in the context as
- // an argument and modifying the context rather than just
- // 'this'
- // testing
- console.log(myApp); //the now populated namespace
- console.log(myApp.utils.getValue()); // test get
- myApp.utils.setValue(25); // test set
- console.log(myApp.utils.getValue());
- console.log(myApp.utils.tools.diagnose());
Angus Croll has also previously suggested the idea of using the call API to provide a natural separation between contexts and arguments. This pattern can feel a lot more like a module creator, but as modules still offer an encapsulation solution, I'll briefly cover it for the sake of thoroghness:
- // define a namespace we can use later
- var ns = ns || {}, ns2 = ns2 || {};
- // the module/namespace creator
- var creator = function(val){
- var val = val || 0;
- this.next = function(){
- return val++
- };
- this.reset = function(){
- val = 0;
- }
- }
- creator.call(ns);
- // ns.next, ns.reset now exist
- creator.call(ns2, 5000);
- // ns2 contains the same methods
- // but has an overridden value for val
- // of 5000
As mentioned, this type of pattern is useful for assigning a similar base set of functionality to multiple modules or namespaces, but I'd really only suggest using it where explicitly declaring your functionality within an object/closure for direct access doesn't make sense.
Conclusions
Reviewing the namespace patterns above, the option that I would personally use for most larger applications is nested object namespacing with the object literal pattern.
IIFEs and single global variables may work fine for applications in the small to medium range, however, larger codebases requiring both namespaces and deep sub-namespaces require a succinct solution that promotes readability and scales. I feel this pattern achieves all of these objectives well.
I would also recommend trying out some of the suggested advanced utility methods for namespace extension as they really can save you time in the long-run.
reference : http://addyosmani.com/blog/essential-js-namespacing/
訂閱:
文章 (Atom)