全球化是不可避免的。
這是一個(gè)古老的討論,但我仍然想補(bǔ)充一些想法,因?yàn)槲覒涯钏麄冊(cè)谏厦嫣岬降拇鸢?。這些答案簡(jiǎn)化了什么是全球性的太多,并提出了根本不是解決問(wèn)題的解決方案。問(wèn)題是:處理全局變量和使用關(guān)鍵字全局的正確方法是什么?要做到這一點(diǎn),我們首先要研究和描述什么是全局的。
看看Zend的這段代碼-請(qǐng)理解我并不認(rèn)為Zend寫得不好:
class DecoratorPluginManager extends AbstractPluginManager{/**
* Default set of decorators
*
* @var array
*/protected $invokableClasses = array(
'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
'htmltag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
'tag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
);
這里有很多不可見的依賴項(xiàng)。這些常量實(shí)際上是類。您還可以在此框架的某些頁(yè)面中看到Required_Onone。SEVENT_ONE是一個(gè)全局依賴項(xiàng),因此會(huì)創(chuàng)建外部依賴項(xiàng)。對(duì)于一個(gè)框架來(lái)說(shuō),這是不可避免的。如果沒有大量依賴的外部代碼,如何創(chuàng)建像DecoratorPluginManager這樣的類?沒有很多額外的東西,它就不能發(fā)揮作用。使用Zend框架,您是否曾經(jīng)更改過(guò)接口的實(shí)現(xiàn)?接口實(shí)際上是全局的。
另一個(gè)全球使用的應(yīng)用程序是Drupal。他們非常關(guān)心正確的設(shè)計(jì),但就像任何大型框架一樣,他們有很多外部依賴??纯催@個(gè)頁(yè)面中的全局:
/**
* @file
* Initiates a browser-based installation of Drupal.
*//**
* Root directory of Drupal installation.
*/define('DRUPAL_ROOT', getcwd());/**
* Global flag to indicate that site is in installation mode.
*/define('MAINTENANCE_MODE', 'install');// Exit early if running an incompatible PHP version to avoid fatal errors.
if (version_compare(PHP_VERSION, '5.2.4') < 0) {
print 'Your PHP installation is too old. Drupal requires at least PHP 5.2.4. See the
<a href="http://drupal.org/requirements">system requirements</a> page for more information.';
exit;}// Start the installer.require_once DRUPAL_ROOT . '/includes/install.core.inc';install_drupal();
寫過(guò)重定向到登錄頁(yè)面嗎?這正在改變?nèi)騼r(jià)值。(然后你不是說(shuō)“WTF”,我認(rèn)為這是對(duì)您的應(yīng)用程序的不良文檔的良好反應(yīng)。)全局的問(wèn)題不是它們是全局的,而是為了有意義的應(yīng)用而需要它們。問(wèn)題在于整個(gè)應(yīng)用程序的復(fù)雜性,這會(huì)使它成為一場(chǎng)噩夢(mèng)。會(huì)話是全局的,$_POST是全局的,Drupal_root是全局的,include/install.core.inc‘是不可修改的全局的。為了讓這個(gè)功能完成它的工作,除了任何函數(shù)之外,還有一個(gè)很大的世界。
戈登的回答是不正確的,因?yàn)樗吖懒艘粋€(gè)函數(shù)的獨(dú)立性,而稱一個(gè)函數(shù)為騙子是過(guò)分簡(jiǎn)化了情況。函數(shù)不會(huì)說(shuō)謊,當(dāng)您查看他的示例時(shí),該函數(shù)的設(shè)計(jì)是不正確的-他的示例是一個(gè)bug。(順便說(shuō)一句,我同意這樣的結(jié)論,即應(yīng)該將代碼解耦。)欺騙的答案并不是對(duì)情況的正確定義。函數(shù)總是在更大的范圍內(nèi)工作,他的例子太簡(jiǎn)單了。我們都會(huì)同意他的觀點(diǎn),即函數(shù)是完全無(wú)用的,因?yàn)樗祷匾粋€(gè)常數(shù)。不管怎么說(shuō),這種功能的設(shè)計(jì)都很糟糕。如果你想證明實(shí)踐是不好的,請(qǐng)?zhí)峁┮粋€(gè)相關(guān)的例子。在整個(gè)應(yīng)用程序中重命名變量并不是什么大不了的,有一個(gè)好的IDE(或一個(gè)工具)。問(wèn)題是變量的作用域,而不是函數(shù)作用域的不同。一個(gè)函數(shù)在過(guò)程中發(fā)揮作用是有適當(dāng)時(shí)間的(這就是為什么首先創(chuàng)建它的原因),在適當(dāng)?shù)臅r(shí)候,它可能會(huì)影響整個(gè)應(yīng)用程序的功能,因此也會(huì)處理全局變量。xzyfer的回答是一種沒有論證的陳述。如果您有過(guò)程功能或OOP設(shè)計(jì),則全局在應(yīng)用程序中同樣存在。接下來(lái)兩種改變?nèi)种档姆椒ū举|(zhì)上是相同的:
function xzy($var){
global $z;
$z = $var;}function setZ($var){
$this->z = $var;}
在這兩種情況下,$z的值都是在特定函數(shù)中更改的。在這兩種編程方式中,您都可以在代碼中的其他地方進(jìn)行這些更改。您可以說(shuō),使用全局,您可以調(diào)用$z在任何地方,并在那里改變。可以,停那兒吧。但你會(huì)嗎?當(dāng)它在不合適的地方做的時(shí)候,它不應(yīng)該被稱為蟲子嗎?
鮑勃·范格對(duì)Xzyfer的評(píng)論。
那么,應(yīng)該有人使用任何東西,尤其是關(guān)鍵字“全局”嗎?不,但就像任何類型的設(shè)計(jì)一樣,試著分析它所依賴的和依賴于它的東西。試著找出它什么時(shí)候變化,以及它是如何變化的。更改全局值應(yīng)該只對(duì)那些可能隨每個(gè)請(qǐng)求/響應(yīng)而變化的變量發(fā)生。也就是說(shuō),只適用于屬于流程功能流的變量,而不屬于其技術(shù)實(shí)現(xiàn)。將URL重定向到登錄頁(yè)面屬于流程的功能流,流程是用于技術(shù)實(shí)現(xiàn)接口的實(shí)現(xiàn)類。您可以在應(yīng)用程序的不同版本中更改后者,但不應(yīng)更改每個(gè)請(qǐng)求/響應(yīng)的版本。
為了進(jìn)一步了解在處理全局詞和關(guān)鍵字全局時(shí)遇到的問(wèn)題,以及什么時(shí)候不是,我將介紹下一句,它來(lái)自Wim de Bie在寫博客時(shí)說(shuō)的話:‘個(gè)人是的,私人的不是’。當(dāng)一個(gè)函數(shù)為了其自身的功能而改變?nèi)肿兞康闹禃r(shí),我將稱之為全局變量和bug的私有使用。但是,當(dāng)全局變量的改變是為了對(duì)整個(gè)應(yīng)用程序進(jìn)行適當(dāng)?shù)奶幚頃r(shí),比如用戶重定向到登錄頁(yè)面,那么在我看來(lái),在我看來(lái)可能是一個(gè)好的設(shè)計(jì),從定義上來(lái)說(shuō)不是不好的,當(dāng)然也不是反模式。
回顧戈登、欺騙和xzyfer的答案:他們都有“私人的是”(和bug)作為例子。這就是為什么他們反對(duì)使用全球化。我也會(huì)這么做的。然而,他們并沒有附帶“個(gè)人是的,私人的不”-就像我在這個(gè)答案中做過(guò)幾次這樣的例子。