PHP设计模式介绍Ⅳ单件模式_PHP教程
几乎所有面向对象的程序中,总有一两个资源被创建出来,在程序应用中持续被共享使用。例如,这样的一个资源,在一个电子商务程序的数据库连接中使用:这个连接在应用程序启动时初始化,程序于是可以有效的执行;当程序结束时,这个连接最终被断开并销毁。如果是你写的代码,没必要在每时每刻创建一个数据库连接,这样非常低效。已经建立好的连接应该能被你的代码简单重复的使用。这个问题就是,基于以上要求你将如何进行这个数据库连接?(或者连接其它被循环使用的唯一资源,比如一个开放文件或者一个队列。)
问题
你怎样确保一个特殊类的实例是独一无二的(它是这个类的唯一实例),并且它很存取容易呢?
解决方案
当然,全局变量是显而易见的解决方案。但它就像潘多拉的盒子(正确的判断来自经验,而错误的判断产生经验。这句谚语就是这个意思。),你的任何代码都能修改全局变量,这将不可避免的引起更多调试的意外。换句话说,全局变量的状态总是会出现一些问题的,(这里有一个关于全局变量使用问题不错的描述,http://c2.com/cgi/wiki?GlobalVariablesAreBad)。
当你需要一个特殊类的唯一实例时,使用这个名字叫单件的模式。基于单件模式的类能实例化和初始化这个类的一个实例,并且提供每时每刻绝对相同的连接。一般情况下使用名为getInstance()的静态方法实现。
关键问题是,如何在每时每刻获得一个精确统一的实例。请看下面的例子:
// PHP4
function TestGetInstance() {
$this->assertIsA(
$obj1 =& DbConn::getInstance(),
‘DbConn’,
‘The returned object is an instance of DbConn’);
$this->assertReference(
$obj1,
$obj2 =& DbConn::getInstance(),
‘Two calls to getInstance() return the same object’);
}
注释:assertReference
assertReference() 方法确保两个被传递的参数引用自相同的PHP变量。
在PHP4中,这里断言两个被测试的参数的却是相同的对象。assertReference() 这个方法在移植到PHP5以后也许就不推荐使用了。
这个test方法有两个断言:第一个判断第调用静态方法DbConn::getInstance()返回的值是DbConn对象的实例,第二个用来判断第二次调用getInstance()方法返回得值引用的是相同的对象实例,这意味着他们使用的是同一个对象。
除了断言代码预期的执行结果,Test也预示了getInstance()的正确用法(PHP4):$local_conn_var=&DbConn::getInstance()。引用(=&)静态方法的返回值赋值给了这个局部变量。
再写另外一段测试代码:直接用“new”来实例化一个单件类会引起某些类型的错误。test代码如下:
function TestBadInstantiate() {
$obj =& new DbConn;
$this->assertErrorPattern(
‘/(bad|nasty|evil|do not|don\’t|warn).*’.
‘(instance|create|new|direct)/i’);
}
这段代码直接创建了一个 DbConn 的实例,将会引起PHP报错。为了让代码更稳定,我们用PCRE正则表达式来匹配报错信息。(显示报错信息的确切措词并不重要。)
[next]
样本代码
单件模式是一个很有趣的模式。让我们用PHP4和PHP5两种方式来探究它的实现过程,现在从PHP4开始。
全局方式
理论上说,一个全局变量可以生成一个完美的单件,但全局变量可能被修改:在代码运行过程中,不能保证全局变量指向的是一个对象。因而,不让全局变量在全局直接引用,就可以减少“太随意访问”这个全局变量的问题。比如说,这段代码使用一个非常长而且独特的名字,从而“隐藏” 了全局变量的引用。
class DbConn {
function DbConn($fromGetInstance=false) {
if (M_E != $fromGetInstance) {
trigger_error(‘The DbConn class is a Singleton,’
.’ please do not instantiate directly.’);
}
}
function &getInstance() {
$key = ‘__some_unique_key_for_the_DbConn_instance__’;
if (!(array_key_exists($key, $GLOBALS) && is_object($GLOBALS[$key])
&& ‘dbconn’ == get_class($GLOBALS[$key]) )) {
$GLOBALS[$key] =& new DbConn(M_E);
}
return $GLOBALS[$key];
}
}
在DbConn的构造函数中,你可能对$fromGetInstance的默认参数感到疑惑。在对象被直接实例化时,它能够提供(很微弱的)保护:除非这个默认值变成e (在PHP的数学常量中 M_E = 2.718281828459),否则这段代码会报错。
表示成一个UML类图,解决办法如下:

如果你不选用这个“神秘参数”-类型保护,建立一个全局标记是另外一个选择,用它来验证你是通过getInstance()方法来创建的对象。保护方式从“你知道它的名字”改变成“它存在于环境中”。
下面有个例子,它解释了为什么构造函数保护代码有一个全局的标识:
class DbConn {
function DbConn() {
$token = ‘__some_DbConn_instance_create_semaphore__’;
if (!array_key_exists($token, $GLOBALS)) {
trigger_error(‘The DbConn class is a Singleton,’
.’ please do not instantiate directly.’);
}
}
function &getInstance() {
static $instance = array();
if (!$instance) {
$token = ‘__some_DbConn_instance_create_semaphore__’;
$GLOBALS[$token] = true;
$instance[0] =& new DbConn;
unset($GLOBALS[$token]);
}
提示
PHP4允许你改变构造函数中$this的值。在过去,我们会习惯设置 $this = null;当有一个创建构造错误时,确保无效的对象不能被代码继续使用。PHP4中很有用的东西,在PHP5中并不兼容,将来会在你的代码中得到验证,这种技术不再被推荐。
这段代码中另外一个重点是引用操作&的用法。有两种地方需要使用&。第一种是在函数定义时,在函数名字前用来表示将返回一个引用。第二种是将新的DbConn对象赋值给$GLOBALS数组。(在序言和值对象章节中提到过:在PHP4中,你总会使用 &操作符,以引用的方式创建、传递和返回对象,)
getInstance()方法的条件检查,常常被写成没有警示的情况下运行,甚至在E_ALL的错误级别下也不会提示。它检查在$GLOBAL数组中适当的位置是否有一个DbConn对象,如果没有,就在那里创建这个对象。这个方法于是返回了这样的结果,这个对象能被重复创建或者这个对象在之前已经被这个方法创建过了。当方法结束时,你可以确认已经拥有这个类的有效实例,而且它已经被有效初始化。
[next]
静态方式
关于全局变量的问题,甚至隐藏在getInstance()中的全局变量中也存在。因为全局变量在脚本的任何地方都有效,在没有注意到的情况下,你依然有可能破坏这个全局变量,
在getInstance()方法内部使用静态变量来存储Singleton是一个显得干净的办法。第一个代码片断如下:
class DbConn {
// ...
function &getInstance() {
static $instance = false;
if (!$instance) $instance =& new DbConn(M_E);
return $instance;
}
}
Zend 1引擎在PHP4中不能存储静态变量的引用 (请看http://www.php.net/manual/en/language.variables.scope.php#AEN3609)。使用一个工作区存储静态数组,并且将这个单件实例的引用放置到一个已知的数组中。getInstance()方法如下:
class DbConn {
function DbConn($fromGetInstance=false) {
if (M_E != $fromGetInstance) {
trigger_error(‘The DbConn class is a Singleton,’
.’ please do not instantiate directly.’);
}
}
function &getInstance() {
static $instance = array();
if (!$instance) $instance0 =& new DbConn(M_E);
return $instance0;
}
}
这段代码很简单的选择了这个静态数组$instancede的第一个元素,用来保持单件DbConns实例的引用。
虽然这段代码有点依赖PHP的布尔方式,但它比那个全局版本更严谨:在条件检测时,使用一个空的数组会得到结果false。就像在DbConn类的前一个版本一样,在函数的定义和赋值部分需要引用操作符。
PHP5中的单件模式
PHP5中更容易实现单件模式,PHP5对于类内部变量和函数的访问控制被加强了。将DbConn::_construct()构造方法设置为私有(private),这个类就不能被直接实例化。用UML图表示,PHP5的DbConn单件模式如下:

组合使用静态方法和静态变量保持这个实例,并且设置构造函数为私有,以防止直接实例化类而创建实例,代码如下:
class DbConn {
/**
* static property to hold singleton instance
*/
static $instance = false;
/**
* constructor
* private so only getInstance() method can instantiate
* @return void
*/
private function __construct() {}
/**
* factory method to return the singleton instance
* @return DbConn
*/
public function getInstance() {
if (!DbConn::$instance) {
DbConn::$instance = new DbConn;
}
return DbConn::$instance;
}
}
注:更多精彩文章请关注帮客之家编程教程栏目。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











PHP 8.4는 상당한 양의 기능 중단 및 제거를 통해 몇 가지 새로운 기능, 보안 개선 및 성능 개선을 제공합니다. 이 가이드에서는 Ubuntu, Debian 또는 해당 파생 제품에서 PHP 8.4를 설치하거나 PHP 8.4로 업그레이드하는 방법을 설명합니다.

VS Code라고도 알려진 Visual Studio Code는 모든 주요 운영 체제에서 사용할 수 있는 무료 소스 코드 편집기 또는 통합 개발 환경(IDE)입니다. 다양한 프로그래밍 언어에 대한 대규모 확장 모음을 통해 VS Code는

이 튜토리얼은 PHP를 사용하여 XML 문서를 효율적으로 처리하는 방법을 보여줍니다. XML (Extensible Markup Language)은 인간의 가독성과 기계 구문 분석을 위해 설계된 다목적 텍스트 기반 마크 업 언어입니다. 일반적으로 데이터 저장 AN에 사용됩니다

숙련된 PHP 개발자라면 이미 그런 일을 해왔다는 느낌을 받을 것입니다. 귀하는 상당한 수의 애플리케이션을 개발하고, 수백만 줄의 코드를 디버깅하고, 여러 스크립트를 수정하여 작업을 수행했습니다.

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

문자열은 문자, 숫자 및 기호를 포함하여 일련의 문자입니다. 이 튜토리얼은 다른 방법을 사용하여 PHP의 주어진 문자열의 모음 수를 계산하는 방법을 배웁니다. 영어의 모음은 A, E, I, O, U이며 대문자 또는 소문자 일 수 있습니다. 모음이란 무엇입니까? 모음은 특정 발음을 나타내는 알파벳 문자입니다. 대문자와 소문자를 포함하여 영어에는 5 개의 모음이 있습니다. a, e, i, o, u 예 1 입력 : String = "Tutorialspoint" 출력 : 6 설명하다 문자열의 "Tutorialspoint"의 모음은 u, o, i, a, o, i입니다. 총 6 개의 위안이 있습니다

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

PHP의 마법 방법은 무엇입니까? PHP의 마법 방법은 다음과 같습니다. 1. \ _ \ _ Construct, 객체를 초기화하는 데 사용됩니다. 2. \ _ \ _ 파괴, 자원을 정리하는 데 사용됩니다. 3. \ _ \ _ 호출, 존재하지 않는 메소드 호출을 처리하십시오. 4. \ _ \ _ get, 동적 속성 액세스를 구현하십시오. 5. \ _ \ _ Set, 동적 속성 설정을 구현하십시오. 이러한 방법은 특정 상황에서 자동으로 호출되어 코드 유연성과 효율성을 향상시킵니다.
