| 
       
	PHP中,变量有全局的概念,比如$_GET $_POST等数组中保存的值都是全局的,如果直接使用一个变量,那么它也是全局可用的,如果在函数中使用global关键字声明一个变量,那这个函数就可以使用来自外部的这个变量值,函数中的这个变量值还可以从函数带出到外部,所有直接声明的变量或用global关键字声明的变量,实际上全部注册到$GLOBALS数组中。比如声明了$var,当要引用这个变量时可以直接用$var或$GLOBALS['var']。这种搞法其实已经非常怪异了,不过还有更加怪异的,比如$_GET['name'],你可能可以使用$name直接引用或用$GLOBALS['name']来引用这个变量(具体决定于PHP的配置,不过一般都是关闭的了)。 这些诡异的用法是PHP的历史原因导致的。不过作为一个PHP程序员,仍然需要知道这个。 
	这里的全局变量的使用有很大风险,比如我声明了一个$var,然后在其它地方再次声明一个同名的$var,那么后面的将悄悄覆盖前面的。更加糟糕的是,如果这个变量引用一个对象,但是由于一些第三方代码的引入,也声明了一个同名的变量,那么这个变量在其它地方调用方法时将出现错误,这个问题很令人烦恼。所以我们得到的教训是:慎用全局变量。 
	以上说得情况在面向过程的代码中中,尤为明显。由于这个问题,全局变量设计模式就产生了。以下主要探讨Magento中的全局设计模式和单态设计模式。 
	Magento中使用如下方法实现了全局设计模式: 
	Mage::register 
	Mage::unregister    
	Mage::registry  
	分别对应注册 和 注销 和 获取全局变量。首先看看注册一个全局变量时发生了什么事情: 
	public static function register($key, $value, $graceful = false) 
	{ 
	    if (isset(self::$_registry[$key])) { 
	        if ($graceful) { 
	            return; 
	        } 
	        self::throwException('Mage registry key "'.$key.'" already exists'); 
	    } 
	    self::$_registry[$key] = $value; 
	} 
	首先检查$key是否存在$_registry数组中,如果存在就根据$graceful的设置,返回空或者抛出异常。如果不存在就直接赋值。可见,一个变量注册了,就不能再注册一个同名的变量了,这个很好解决了变量被覆盖的威胁。但是还是有不足,因为程序员可以先调用unregister来注销变量,然后设置自己的变量: 
	public static function unregister($key) 
	{ 
	    if (isset(self::$_registry[$key])) { 
	        if (is_object(self::$_registry[$key]) && (method_exists(self::$_registry[$key], '__destruct'))) { 
	            self::$_registry[$key]->__destruct(); 
	        } 
	        unset(self::$_registry[$key]); 
	    } 
	} 
	注销全局变量时如果全局变量是对象并且设置了__destruct析构函数,那么直接调用它的析构函数释放资源。否则就是简单unset,这个就依赖PHP的垃圾回收器来回收了。 
	当想要获取这个全局变量时,直接调用registry,可以把它看做是注册表: 
	public static function registry($key) 
	{ 
	    if (isset(self::$_registry[$key])) { 
	        return self::$_registry[$key]; 
	    } 
	    return null; 
	} 
	Magento内核高度使用这个模式,我们知道Magento中的控制器并不会直接和视图交互,真正和视图交互的是Block,控制器中只要使用renderLayout就可以获取输出: 
	1 
	2 
	3 
	$this->loadLayout(); 
	$this->getLayout()->getBlock('content')->setSomeVar($var); 
	$this->renderLayout(); 
	我们可以在控制器中添加: 
	Mage::register('product', $product); 
	一个Block中可能包含如下方法: 
	public function getProduct() 
	{ 
	    return Mage::registry('product'); 
	} 
	这样就可以在视图中使用: 
	echo $this->getProduct()->getName(); 
	Magento中的单态设计模式(Singleton Pattern) 
	获取一个对象的一份单态实例: 
	Mage::getSingleton('group/class'); 
	过多解释在面对代码时非常苍白,所以我们这里直接看看这个方法的实现: 
	#File: app/Mage.php 
	public static function getSingleton($modelClass='', array $arguments=array()) 
	{ 
	    $registryKey = '_singleton/'.$modelClass; 
	    if (!self::registry($registryKey)) { 
	        self::register($registryKey, self::getModel($modelClass, $arguments)); 
	    } 
	    return self::registry($registryKey); 
	} 
	它使用’_singleton/’.$modelClass组建名字,然后调用register把getModel()返回的实例记录到注册表中,你可以看到,如果这个名称对应的值存在了,直接就放回这个实例,就是这样保证了全局唯一(看起来不是严格的单态模式,因为可以unregister)。这个封装另一个模式来实现的别的设计模式,也算是一个亮点吧。不过一般单态设计模式是控制类的构造函数来保证的,常见的使用方法是: 
	1 
	$bar = Object_Type::getInstance(); 
	可是Magento中并没有采用这种方式。尽管可以unregister,但是它的灵活性也体现出来了。 
      
      (责任编辑:最模板) | 
    
