在PHP中开发7个面向对象的良好习惯
如果您还没有建立OO原则来创建应用程序,那么就使用PHP的面向对象(OO)语言特性。这7个习惯将帮助您开始在过程编程和OO编程之间转换。在PHP编程的早期阶段,PHP代码基本上限于面向过程。过程代码的特点是在使用过程中构建应用程序块。
然而,没有面向对象的语言结构,程序员仍然可以引入面向对象的特性,为PHP代码。这是一个有点困难,使代码难以阅读,因为它是一个混合的模式(一个伪OO设计过程语言),使用面向对象的结构在PHP代码,例如,定义和使用类的能力,继承类之间建立关系,可以定义接口,它是更容易建立符合良好的面向对象的操作规范。
Although no over modularized pure process design is running well, the advantages of OO design are shown on maintenance.Because most of the lifecycle of a typical application is spent on maintenance, code maintenance is an important part of the life cycle of the application.And code maintenance is easily forgotten during the development process.If there is competition in application development and deployment, long-term maintainability may be placed in a secondary position.
模块化——一个优秀的OO设计的主要特征之一——可以帮助完成这样的维护。模块化将有助于封装更改,以便随着时间的推移,应用程序可以更容易地扩展和修改。
在一般情况下,有超过7的习惯,建立面向对象的软件,但以下的7个习惯这里可以使代码符合基本的面向对象的设计标准,他们将为你建立更多的面向对象的习惯和建立软件易于维护和扩展的一个强大的基础。这些习惯集中在几个模块的主要特征。关于面向对象设计的独立的语言优势的更多信息,请参阅参考资料。
7个优秀的PHP习惯包括:
保持谦卑。
做个好邻居。
避免看到美杜莎。
使用最弱的环节。
你是橡皮,我是胶水。
限制蔓延。
考虑使用模式。
保持谦虚
保持谦逊意味着不让自己暴露在课堂的实现和功能的实现中。隐藏信息是一个基本习惯。如果你不能养成隐藏细节的习惯,那么很难养成其他习惯。信息隐藏也被称为封装。
有许多公共领域的直接原因是一个坏习惯,和最重要的原因是你不在实施变化做出了正确的选择。面向对象的概念是用来隔离和封装变化,确保变更没有本质的病毒起着不可或缺的作用(病毒)的性质发生变化,病毒的变化是在开始一个非常小的变化,如改变三个元素的数组的数组只包含两个元素。突然间,你发现你需要改变更多的代码来适应一个很微不足道的变化。
开始隐藏信息的一个简单方法是保持字段私有并用公共访问方法公开字段,就像在家中的窗口一样。它不能使整个墙对外开放,但只打开一个或两个窗口。(我将介绍有关访问方法的良好习惯的更多信息:使用公共访问方法)。
除了允许您的实现隐藏在更改之外,使用公共访问方法而不是直接打开该字段将允许您在基本实现的基础上进行构建。该方法实现了与父方法略有不同的行为,用于实现覆盖访问方法,它还允许您构建抽象实现,以便将实际实现委派给包含基本实现的类。
坏习惯:公共领域
在清单1的坏代码示例中,人对象的字段直接暴露于公共字段,而不是使用访问方法。
清单1。公共领域的坏习惯
复制代码代码如下所示:
< PHP
班上的人
{
公共前缀;
公众givenName美元;
美元的公共;
公共$后缀;
}
人=新人();
元>前缀>先生;
$人-> givenName =约翰;
回声($ -前缀);
回声($人-> givenName);
>
如果在对象的任何变化,所有的代码,使用对象也需要改变。例如,如果某人的名字,姓氏和名字都被封装到PersonName对象,你需要修改代码来改变一切。
良好习惯:使用公共访问方法
采用优秀的面向对象的习惯(参见清单2),同一个对象现在有私人领域而不是公共领域,它是谨慎暴露私人领域公共调用get和set访问公共方法。这些方法获得现在提供从PHP类获取信息的一种常用方法,使改变所有使用该类的代码的需求可能减少实施时的变化。
清单2。使用公共存取方法的好习惯
复制代码代码如下所示:
< PHP
班上的人
{
私人$前缀;
私人givenName美元;
私人的美元;
私人$后缀;
公共职能setPrefix($前缀)
{
$ >前缀= $前缀;
}
公共功能getprefix()
{
返回$ -前缀;
}
公共功能setgivenname(美元计)
{
美元-> givenName = $ GN;
}
公共功能getgivenname()
{
返回这个-> givenName;
}
公共功能setfamilyname($ FN)
{
美元->的= $ FN;
}
公共功能getfamilyname()
{
返回这个>的;
}
公共功能setsuffix($后缀)
{
$ >后缀=后缀;
}
公共功能getsuffix()
{
返回$后缀;
}
}
人=新人();
$人-> setPrefix();
$人-> setgivenname(约翰);
回声($人-> getprefix());
回声($人-> getgivenname());
>
乍一看,这段代码可能会做很多工作,实际上它可能在前端工作更多,但是,从长远来看,使用优秀的OO习惯是非常划算的,因为未来的变化将大大巩固。
在清单3所示的代码版本中,我更改了内部实现,使用名称部分的关联数组。理想情况下,我希望更仔细地处理错误并检查元素的存在,但本例的目的是说明使用我的类的代码不需要更改。代码不知道类的变化。记住使用OO习惯的原因是仔细封装更改,以便代码更具扩展性和更易于维护。
清单3。使用不同内部实现的另一个例子
复制代码代码如下所示:
< PHP
班上的人
{
私人姓名=阵列(美元);
公共职能setPrefix($前缀)
{
美元->姓名{ } = $前缀'prefix;
}
公共功能getprefix()
{
返回这个->姓名{ 'prefix};
}
公共功能setgivenname(美元计)
{
美元->姓名{ 'givenname} = $ GN;
}
公共功能getgivenname()
{
返回这个->姓名{ 'givenname};
}
…
}
*
即使内部实现改变了,这里的代码仍然保持不变。
*相同。更改仅封装到人员类中。
* /
人=新人();
$人-> setPrefix();
$人-> setgivenname(约翰);
回声($人-> getprefix());
回声($人-> getgivenname());
>
做个好邻居
创建一个类的时候,应该正确对待自己的错误。如果类不知道如何处理错误,这些错误应该被封装在由呼叫者了解格式。此外,避免返回一个空的对象或对象不处于无效状态。在许多情况下,它是可能的为了实现这一只有检查的参数将解释的参数失效的具体原因例外。当你养成这种习惯,它可以帮助你保持代码或人使用对象-节省很多时间。
坏习惯:不要犯错误。
考虑清单4中的例子,这个例子将接受一些参数和返回的人,对象填充一些价值。然而,在parsePersonName()方法,它不验证是否提供瓦尔美元变为空,它是否是一个零长度字符串,或字符串是否是未格式化的格式。parsePersonName()方法不返回的人,对象,但返回null。管理员或程序员使用这种方法可能会觉得很麻烦,至少他们现在需要开始设置断点和调试PHP脚本。
清单4。不犯错误或处理错误的坏习惯
复制代码代码如下所示:
类personutils
{
公共静态函数parsePersonName($格式,为Val)
{
如果(strpos(
人=新人();
$部分=拆分($ );假设值是最后一个,第一个
$人-> setgivenname($部分{ 1 });
$人-> setfamilyname($部分{ 0 });
}
还美元;
}
}
parsePersonName()在清单4中的方法可以修改初始化Person对象之外,如果条件,确保一个有效的人物总是得到。不过,你一个人没有设置属性,它仍然没有改善你的困境。
好习惯:每个模块都处理自己的错误。
而不是让对方猜出空气,参数是预先验证。如果不设置变量不能产生有效的结果,检查变量,把invalidargumentexception。如果字符串是否为空或必须在一个特定的格式,请检查格式和抛出异常。清单5解释如何创建例外,在parseperson一些新的条件()方法,演示了一些基本的验证。
清单5。犯错误的好习惯
复制代码代码如下所示:
< PHP
类invalidpersonnameformatexception延伸logicexception { }
类personutils
{
公共静态函数parsePersonName($格式,为Val)
{
如果(!$格式){
把新的invalidpersonnameformatexception(无效的姓名格式。);
}
(如果)!isset($ Val))| | strlen(Val = = 0美元)){
把新的invalidargumentexception(必须进行解析,提供一个非空值);
}
}
}
>
最终的目标是希望人们可以使用你的类没有了解工作的原则。如果他们使用的方法不正确或不使用所需的方式,没有必要去猜他们为什么不能工作。作为一个好邻居,你需要知道那些重复使用为你的类是不特定的,所以你需要解决的问题的猜测。
避免看Medusa
当我第一次学到的面向对象的概念,我很怀疑这个界面真的很有帮助。我的同事给了我一个例子,即不使用接口就像看到美杜莎的头。在Greek神话中,美杜莎,蛇发女怪长。谁看着她将成为Perle Hughes石。杀了美杜莎通过观察在保护她的影子,避免变成石头的面对她。
界面处理美杜莎的镜子,当你用一个具体的实现,代码也必须在实现代码的变化,实施直接使用会限制你的选择,因为你基本上把课堂变成了一块石头。
坏习惯:没有界面
清单6显示了从数据库加载人对象的示例,它将获得此人的姓名,并返回与数据库中匹配的人对象。
清单6。不使用接口的坏习惯
复制代码代码如下所示:
< PHP
类dbpersonprovider
{
公共职能GetPerson($ givenName,$的)
{
转到get数据库…
人=新人();
$人-> setPrefix();
$人-> setgivenname(约翰);
还美元;
}
}
我需要获取个人数据…
DBPersonProvider()美元=新供应商;
人=美元美元供应商-> GetPerson(约翰
回声($人-> getprefix());
回声($人-> getgivenname());
>
环境变化之前,代码从数据库中加载的人能够正常地运行。例如,从数据库加载的人可能会被应用到应用程序的第一个版本,但是第二版,你可能需要添加的功能从Web服务人员。事实上,这类已成为石头因为它直接使用实现类,可现在的变化是非常有限的。
良好习惯:使用界面
清单7显示了一个示例代码没有经过加载用户的新方法的实施改变了。这个例子说明一个接口称为personprovider,将申报单的方法。如果任何代码使用personprovider,代码是禁止直接使用实现类。相反,就像是用personprovider作为一个实际的对象。
清单7。使用接口的好习惯
复制代码代码如下所示:
< PHP
接口personprovider
{
公共职能GetPerson($ givenName,$的);
}
dbpersonprovider personprovider类实现
{
公共职能GetPerson($ givenName,$的)
{
假装去*数据库,得到这个人…
人=新人();
$人-> setPrefix();
$人-> setgivenname(约翰);
还美元;
}
}
类personproviderfactory
{
公共静态函数createprovider(合型)
{
如果(合型= 'database)
{
返回新的dbpersonprovider();
{人}
返回新的nullprovider();
}
}
}
$配置= 'database;
我需要获取个人数据…
提供者::createprovider = personproviderfactory美元(美元配置);
人=美元美元供应商-> GetPerson(约翰
回声($人-> getprefix());
回声($人-> getgivenname());
>
在使用接口时,尽量避免直接引用实现类。相反,对象外部的内容可以提供正确的实现。如果您的类将基于一些逻辑加载实现,它仍然需要得到所有实现类的定义,但这并没有产生任何效果。
您可以使用工厂模式来创建实现接口的实现类的实例,根据惯例,工厂方法将从创建和返回接口开始,它可以为工厂提供必要的参数来计算应该返回哪一个实现类。
在清单7中,该createprovider()方法只会type.if美元$类型设置为数据库,本厂将回到dbpersonprovider实例。任何新的人员实现从数据库中加载,不需要在使用工厂和interface.dbpersonprovider类的任何变化将实施personprovider接口有GetPerson实际执行()方法。
使用最弱的环节
松散耦合的模块是一个好东西;它是一种性能让你封装变化。其它两个习惯谨慎和避免看到美杜莎-可以帮助你建立一个松散耦合的模块。为了实现松散耦合的类,它可以通过减少类之间的依赖关系习惯了。
坏习惯:紧密耦合
在清单8中,减少依赖关系不必减少客户机对对象使用的依赖性。相反,这个示例将演示如何减少对正确类的依赖,并最小化依赖项。
清单8。紧密结合在一起的坏习惯
复制代码代码如下所示:
< PHP
require_once 。 / addressformatters .php;
类地址
{
私人addressline1美元;
私人addressline2美元;
私人城市;
私有$国家; /或省…
私人$邮编;
私人国家;
公共功能setaddressline1(合线)
{
美元-> addressline1 = $ 1;
}
*访问器等*…
公共职能GetCountry()
{
返回$ >国家;
}
公共功能格式($类型)
{
如果($ =内联){
格式化程序=新InlineAddressFormatter()美元;
否则如果}(合型= =行){
格式化程序=新multilineaddressformatter(美元);
{人}
格式化程序=新NullAddressFormatter()美元;
}
返回格式化程序->格式(美元-> getaddressline1()),
美元-> getaddressline2(),
美元-> getcity(),美元-> getState(),()getpostalcode美元->,
美元-> GetCountry());
}
}
新地址addr = $();
$地址-> setaddressline1(123圣);
$地址-> setaddressline2(步骤200);
$地址-> setcity(某某镇);
$地址-> setstate(是);
$地址-> setpostalcode(55555 -0000 );
$地址-> setcountry(我们);
回声($地址->格式(行));
回声();
回声($地址->格式(内联));
回声();
>
在地址对象上调用格式()方法的代码看起来可能很棒。此代码是利用地址类,调用格式()和完成它。相反,通讯类是不幸运的。它需要知道各种格式的方法,用正确的格式,这可能使地址对象不能重复利用别人,尤其是当其他人都没有用在格式格式化方法课感兴趣()方法。虽然没有对使用地址代码更依赖,地址类有很多代码,它可能只是一个简单的数据对象。
地址类与实现类紧密耦合,该类知道如何格式化地址对象。
良好习惯:对象之间松散耦合
建立一个良好的OO设计的时候,我们必须把关注点分离的概念(SOC)。SoC意味着不同的对象,什么是真正的关心,从而降低耦合度,在原来的地址类,它必须关注如何格式。这可能不是一个好的设计。然而地址类,应考虑到地址的部分,和一些格式化的方法应注意如何正确格式的地址。
在清单9中,该格式的地址代码移动到接口,实现类,和工厂形成使用接口的习惯。现在的addressformatutils类负责创建格式化方法和格式的地址。任何其他对象可以使用的地址,而不必担心得到格式化的方法定义。
清单9。松开对象之间的耦合的好习惯
复制代码代码如下所示:
< PHP
接口addressformatter
{
公共函数的格式(addressline1美元,addressline2美元美元美元,城市,国家,
为美元,美元的国家);
}
multilineaddressformatter addressformatter类实现
{
公共函数的格式(addressline1美元,addressline2美元美元美元,城市,国家,
为美元,美元的国家)
{
返回sprintf(%s%s%s、%s %s
addressline1美元,addressline2美元,美元美元美元的国家,城市,邮政编码,为国家);
}
}
inlineaddressformatter addressformatter类实现
{
公共函数的格式(addressline1美元,addressline2美元美元美元,城市,国家,
为美元,美元的国家)
{
返回sprintf(%s %s,%s,%s %s %s
addressline1美元,addressline2美元,美元美元美元的国家,城市,邮政编码,为国家);
}
}
类addressformatutils
{
公共静态函数formataddress(合式,$地址)
{
格式化程序= addressformatutils::createaddressformatter美元(合型);
返回格式化程序->格式($地址-> getaddressline1()),
$地址-> getaddressline2(),
地址:getcity(美元)(美元),地址-> getState(),
$地址-> getpostalcode(),
$地址-> GetCountry());
}
静态函数createaddressformatter(合型)
{
如果($ =内联){
格式化程序=新InlineAddressFormatter()美元;
否则如果}(合型= =行){
格式化程序=新multilineaddressformatter(美元);
{人}
格式化程序=新NullAddressFormatter()美元;
}
返回格式化程序;
}
}
新地址addr = $();
$地址-> setaddressline1(123圣);
$地址-> setaddressline2(步骤200);
$地址-> setcity(某某镇);
$地址-> setstate(是);
$地址-> setpostalcode(55555 -0000 );
$地址-> setcountry(我们);
回声(addressformatutils::formataddress(行
回声();
回声(addressformatutils::formataddress(内联
回声();
>
当然,缺点是,只要使用了模式,它通常意味着工件(类、文件)的数量会增加,但是它可以通过减少每个类中的维护来弥补这个缺点,甚至在您获得正确的重用性时甚至减少工作量。
你是橡皮,我是胶水
具有高度内聚力的OO设计被集中和组织到相关的模块中,理解关注点对于确定与函数和类的紧密程度是很重要的。
坏习惯:减少凝聚力
当设计的内聚力低,不能组织类和方法,意大利面代码(意大利面代码)经常被用来描述类和方法,捆绑在一起,并具有较低的凝聚力。清单10提供的意大利面代码实例。相对一般的工具类将使用许多不同的对象和有很多的依赖。它执行许多操作,很难实现重用。
清单10。减少凝聚力的坏习惯
复制代码代码如下所示:
< PHP
类工具
{
公共静态函数formataddress($ formattype,地址1美元,
演说2美元美元美元,城市,国家)
{
返回一些地址字符串;
}
公共静态函数formatpersonname(formattype美元,$ givenName,
美元的)
{
返回某人的姓名;
}
公共静态函数parseaddress(formattype美元,美元的价值)
{
真正的实现将设置值等。
返回新地址();
}
公共静态函数parsetelephonenumber(formattype美元,美元的价值)
{
真正的实现将设置值等。
返回新的电话号码();
}
}
>
良好习惯:使用高内聚
高内聚指类和方法相关的组合在一起。如果方法和类有高度凝聚力,整个团队可以很容易分解而不影响设计,设计具有很高的凝聚力将降低耦合提供机会。清单11显示了两个方法,组织成类。的addressutils类将包含一个用于处理地址类的方法,显示地址的相关方法之间的高内聚。以同样的方式,personutils将包括一个方法,专门处理人的对象。这两类新方法与高内聚耦合非常低,因为他们可以完全独立地使用。
清单11中高内聚的良好习惯。
复制代码代码如下所示:
< PHP
类addressutils
{
公共静态函数formataddress($ formattype,地址1美元,
演说2美元美元美元,城市,国家)
{
返回一些地址字符串;
}
公共静态函数parseaddress(formattype美元,美元的价值)
{
真正的实现将设置值等。
返回新地址();
}
}
类personutils
{
公共静态函数formatpersonname(formattype美元,$ givenName,
美元的)
{
一些人名返回;
}
公共静态函数parsePersonName(formattype美元,美元的价值)
{
真正的实现将设置值等。
返回新的姓名();
}
}
>
有限的通信
我经常告诉我的软件团队成员(其中我是一个技术总监或建筑师),面向对象语言的最大的敌人是复制和粘贴操作。使用时在预OO设计的情况下,没有操作的类之间复制代码具有破坏性的。每当你想复制代码从一个班班,请停下来,考虑如何使用类层次结构,利用相似的功能或功能。在大多数情况下,用优良的设计后,你会发现没有需要复制的代码在所有。
坏习惯:不要使用类层次结构
清单12展示了一个局部类的简单示例,它们从重复的字段和方法开始——从长远来看,它不利于应用程序进行更改。
清单12。不使用等级制度的坏习惯
复制代码代码如下所示:
< PHP
班上的人
{
私人givenName美元;
私人的美元;
}
员工类
{
私人givenName美元;
私人的美元;
}
>
继承是开始艰难的习惯,因为它通常需要大量的时间来建立正确的遗传模型分析。反过来,它只需几秒钟用Ctrl+C组合键和Ctrl + V组合键建立一个新的实现。但这部分的时间通常很快胶印在维护阶段,因为应用程序会花费很多的维护。
好习惯:使用继承
在清单13中,新员工类将扩展人类。它现在将继承所有的常用方法和不重新实现这些方法。此外,清单13显示了使用抽象方法,演示了如何把基本功能为基类和如何防止类的实现使用特定功能。
清单13。继承遗产的好习惯
复制代码代码如下所示:
< PHP
抽象的人
{
私人givenName美元;
私人的美元;
公共功能setgivenname(美元计)
{
美元-> givenName = $ GN;
}
公共功能getgivenname()
{
返回这个-> givenName;
}
公共功能setfamilyname($ FN)
{
美元->的= $ FN;
}
公共功能getfamilyname()
{
返回这个>的;
}
公共函数sayHello()
{
回声(你好,我是);
美元-> introduceself();
}
摘要公共功能introduceself();
}
职类员工延伸人
{
私人角色;
公共功能setrole(r)
{
$;
}
公共功能getrole()
{
返回$这个角色;
}
公共功能introduceself()
{
回声(美元-> getrole()。。美元-> getgivenname()。。
美元-> getfamilyname());
}
}
>
考虑使用模式
设计模式是指对象和方法之间的共同作用,并证明了它能解决一些问题。当你考虑使用设计模式,你需要知道如何互动类之间。它是一个简单的方法来建立类和它们之间的相互作用,而不需要重复从成熟的设计人和受益错误。
坏习惯:一次考虑
事实上,没有适当的代码示例演示如何考虑使用模式(尽管有很多优秀的示例可以显示模式实现),但是,一般来说,您知道在满足以下条件的情况下您只能考虑一个对象:
对象模型不是预先设计的。
开始编写单个方法而不删除大多数模型。
我们更喜欢在不使用会话中的设计模式名称的情况下谈论实现。
良好习惯:同时将对象添加到模式中
一般来说,当您执行以下操作时,您正在考虑使用模式:
提前构建班级及其互动。
根据模式应用类。
使用模式名称,如工厂、单例和门面。
删除大部分模型并开始添加实现。
结语
在PHP中开发良好的OO习惯将有助于构建更稳定、更易于维护和更易于扩展的应用程序:
小心.
做个好邻居。
避免看到美杜莎。
使用最弱的环节。
你是橡胶,我是胶水。
限制蔓延。
考虑使用模式。
当您开发并应用这些习惯时,您可能会惊讶地发现应用程序的质量有了飞跃。