|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
那么接下来,这就算学会啦?NO,NO,NO,还早呢,你至尽还没碰过OOP之类的吧?模板呢? 在这个系列文章的最初一局部,作者会商了Zend引擎带来的对象模子,出格提到它与PHP的前几个版本中的模子有甚么分歧。
当1997年炎天,宣布的PHP3中没有企图要使PHP具有面向对象的才能. 事先没有任何与类和对象有关的设法. PHP3是一个地道面向进程的言语. 然而,在1997.8.27的早晨PHP3 alpha版中增添了对类的撑持. 增添一个新特征给PHP,事先仅需求少少的会商,由于事先探究PHP的人太少. 因而从1997年八月起, PHP迈出了走向面向对象编程言语的第一步.
的确,这只是第一步. 由于在这个设计中只要少少的相干的设法,关于对象的撑持不敷壮大. 这个版本中利用对象仅是会见数组的一个很酷的办法罢了. 代替利用$foo[“bar”],你可使用看起来更大度的$foo->bar. 面向对象办法的次要的优势是经由过程成员函数或办法来贮存功效. 例子1中显示了一个典范的代码块. 然而它和例6.19中的做法其实并没有太大分歧.
Listing1 PHP 3 object-oriented programming PHP3中的面向对象编程
class Example
{
var $value = "some value";
function PrintValue()
{
print $this->value;
}
}
$obj = new Example();
$obj->PrintValue();
?>
Listing2 PHP 3 structural programming PHP3 PHP3中的布局化编程
function PrintValue($arr)
{
print $arr["value"];
}
function CreateExample()
{
$arr["value"] = "some value";
$arr["PrintValue"] = "PrintValue";
return $arr;
}
$arr = CreateExample();
//Use PHP's indirect reference
$arr["PrintValue"]($arr);
?>
以上咱们在类中写上两行代码,或显示地传递数组给函数. 但思索到PHP3中这两种选择并没有任何分歧,咱们依然可以仅把对象模子当做一种”语法上的掩饰”来会见数组.
想要用PHP来停止面向对象开辟的人们,出格是想利用设计形式的人,很快就发明他们受阻了. 侥幸地,事先(PHP3时期)没有太多人想用PHP来停止面向对象开辟.
PHP4改动了这类情形. 新的版本带来了援用(reference)的概念, 它答应PHP的分歧标识符指向内存中的统一个地址. 这意味着你可使用两个或更多的称号来给统一个变量定名,就像例3那样.
Listing3 PHP 4 references PHP4中的援用
$a = 5;
//$b points to the same place in memory as $a $b与$a指向内存中同个地址
$b = &$a;
//we're changing $b, since $a is pointing to 改动$b,指向的地址改动
//the same place - it changes too $a指向的地址也改动
$b = 7;
//prints 7 输入7
print $a;
?>
因为构建一个指向彼此的对象收集是一切面向对象设计形式的基本,这个改善具有十分严重的意义.当援用答应创立更多壮大的面向对象使用法式, PHP看待对象和其它类型数据不异的做法带给开辟者极大的疾苦.就像任何PHP4的法式员将会告知你的, 使用法式将会遭受WTMA(Way Too Many Ampersands过量&)综合症. 假如你想构建一个实践使用,你会感应极其疾苦,看看例3你就分明.
Listing3 Problems with objects in PHP 4 PHP4中利用对象的成绩
1 class MyFoo {
2 function MyFoo()
3 {
4 $this->me = &$this;
5 $this->value = 5;
6 }
7
8 function setValue($val)
9 {
10 $this->value = $val;
11 }
12
13 function getValue()
14 {
15 return $this->value;
16 }
17
18 function getValueFromMe()
19 {
20 return $this->me->value;
21 }
22 }
23
24 function CreateObject($class_type)
25 {
26 switch ($class_type) {
27 case "foo":
28 $obj = new MyFoo();
29 break;
30 case "bar":
31 $obj = new MyBar();
32 break;
33 }
34 return $obj;
35 }
36
37 $global_obj = CreateObject ("foo");
38 $global_obj->setValue(7);
39
40 print "Value is " . $global_obj->getValue() . "n";
41 print "Value is " . $global_obj->getValueFromMe() . "n";
让咱们一步步来会商. 起首,有一个MyFoo类.在机关函数里,咱们给$this->me一个援用,并设定有其它三个成员函数: 一个设定this->value的值;一个前往this->value的值;另外一个前往this->value->me的值. 然而--$this不是不异的器材吗? MyFoo::getValue()和MyFoo::getValueFromMe()前往的值不是一样的吗?
起首,咱们挪用CreateObject("foo"),这会前往一个MyFoo类型的对象. 然后咱们挪用MyFoo::setValue(7). 最初,咱们挪用MyFoo::getValue() 和MyFoo::getValueFromMe(), 希冀失掉前往值7。
固然,假如咱们在任何情形下都失掉7, 以上这个例子将不是本书中最没成心义的例子。所以我信任你已猜到―咱们得不到两个7如许的了局。
然而咱们将失掉甚么了局,而且更主要地,为何呢?
咱们将失掉的了局分离是7和5. 至于为何―--有三个很好的来由.
起首,看机关函数. 当在机关函数外部,咱们在this和this->me间创立援用. 换句话说,this和this->me是同个器材. 然而咱们是在机关函数内. 当机关函数停止,PHP要从头创立对象(new MyFoo的了局,第28行)分派给$obj. 由于对象没有特别化看待,就像其它任何数据类型一样,赋值X给Y意味着Y是X的一个正本. 也就是说,obj将是new MyFoo的一个正本,而new MyFoo是一个存在于机关函数的对象. Obj->me怎样呢? 由于它是一个援用,它原封不动依然指向本来的对象―this. Voila-obj和obj->me不再是同个器材了―改动个中一个另外一个不变。
以上是第一层次由. 还有其它相似于第一条的来由. 事业般地咱们盘算克制实例化对象这个成绩(第28行). 一旦咱们把CreateObject前往的值赋给global_object,咱们依然要撞上不异的成绩―global_object将酿成前往值的一个正本,而且再次地,global_object和global_object->me将不再不异. 这就是第二层次由。
然而,现实上咱们还走不了那末远― 一旦CreateObject前往$obj,咱们将损坏援用(第34行) . 这就是第三层次由。
那末,咱们若何更正这些? 有两个选择:一是在一切中央增添&符号,就像例4那样(第24, 28, 31, 37行)。二.假如你侥幸地利用上了PHP5,你可以忘了以上这一切,PHP5会主动为你思索这些。假如你想晓得PHP5是若何思索这些成绩的,持续浏览下去。
Listing4 WTMA syndrome in PHP 4 PHP4中的WTMA综合症
1 class MyFoo {
2 function MyFoo()
3 {
4 $this->me = &$this;
5 $this->value = 2;
6 }
7
8 function setValue($val)
9 {
10 $this->value = $val;
11 }
12
13 function getValue()
14 {
15 return $this->value;
16 }
17
18 function getValueFromMe()
19 {
20 return $this->me->value;
21 }
22 };
23
24 function &CreateObject($class_type)
25 {
26 switch ($class_type) {
27 case "foo":
28 $obj =& new MyFoo();
29 break;
30 case "bar":
31 $obj =& new MyBar();
32 break;
33 }
34 return $obj;
35 }
36
37 $global_obj =& CreateObject ("foo");
38 $global_obj->setValue(7);
39
40 print "Value is " . $global_obj->getValue() . "n";
41 print "Value is " . $global_obj->getValueFromMe() . "n";
PHP5是第一个把对象当作与其它类型数据分歧的PHP版本. 从用户的角度看,这证实它十分分明的体例―在PHP5中,对象老是经由过程援用来传递,而其它类型数据(如integer,string,array)都是经由过程值来传递. 最明显地,没有需要再用&符号来暗示经由过程援用来传递对象了.
面向对象编程普遍使用了对象收集和对象间的庞杂关系,这些都需求用到援用,在PHP的前些版本中,需求显示地指明援用。因而, 如今默许用援用来挪动对象,而且只要在明白请求复制时才复制对象,如许比之前更好。
它是若何完成的呢?
在PHP5之前,一切值都存在一个名为zval(Zend Value)的特别布局里. 这些值可以存入复杂的值,如数字和字符串,或庞杂的值如数组和对象。当值传给函数或从函数前往时,这些值会被复制,在内存的另外一个地址创立一个带有不异内容的布局。
在PHP5中,值仍存为zval布局中,但对象除外. 对象存在一个叫做Object Store的布局里,而且每一个对象有一个分歧的ID. Zval中,不贮存对象自己,而是存着对象的指针. 当复制一个持有对象的zval布局,例如咱们把一个对象当做参数传给某个函数,咱们不再复制任何数据. 咱们仅仅坚持不异的对象指针并由另外一个zval告诉如今这个特定的对象指向的Object Store. 由于对象自己位于Object Store,咱们对它所作的任何改动将影响到一切持有该对象指针的zval布局.这类附加的直接感化使PHP对象看起来就像老是经由过程援用来传递,用通明和无效率的体例.
利用PHP5,咱们如今可以回到示例3,除去一切的&符号, 一切代码都依然可以正常任务。当咱们在机关函数(第4行)中持有一个援用时一个&符号都不必。培训的第四阶段,就是应用PHP语言开发实际的程序。以结合实际的项目开发来进行学习,效果真的很好,在学习完之后就开始练习,能比较容易掌握所学的知识,这是学校的学习所没法比的。 |
|