设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

PHP开发:从程序化到面向对象

2013-7-9 12:00| 发布者: 红黑魂| 查看: 3146| 评论: 0|来自: 51CTO

摘要: 教程详情• 难度: 中级• 预计完成时间: 60分钟这份教程的诞生源自一年多之前Robert C.Martin在演讲中带给我的启发。当时他的演讲主题在于讨论创造“终极编程语言”的可能性。在过程中,他提出了这样几个问题:为什 ...

从逻辑中分离表示

某些函数的作用非常明确——只用于在屏幕上输出信息,但有些函数则用于判断触发条件,更有些函数身兼两种作用。面对这种情况,我们往往最好把这些存在特殊用途的函数放在属于自己的文件当中。我们首先整理只用于屏幕信息输出的函数,并将其转移到functions_display.php文件当中。具体做法如下所示:

  1. function printHome() {  
  2.    print('Welcome to Google Calendar over NetTuts Example');  
  3. }  
  4.    
  5. function printMenu() {  
  6.    putLink('?home''Home');  
  7.    putLink('?showCalendars''Show Calendars');  
  8.    putLink('?logout''Log Out');  
  9.    print('<br><br>');  
  10. }  
  11.    
  12. function putLink($href$text) {  
  13.    print(sprintf('<a href="%s" style="font-size:12px;margin-left:10px;">%s</a> | '$href$text));  
  14. }  
  15.    
  16. function putTitle($text) {  
  17.    print(sprintf('<h3 style="font-size:16px;color:green;">%s</h3>'$text));  
  18. }  
  19.    
  20. function putBlock($text) {  
  21.    print('<div display="block">'.$text.'</div>');  
  22. }  

要完成剩余的表示分离工作,我们需要从方法中提取出表示部分。下面我们就以单一方法为例演示这一过程:

  1. function printEventDetails() {  
  2.    global $client;  
  3.    foreach (retrieveEvents($_GET['calendarId']) as $event)  
  4.       if ($event['id'] == $_GET['showThisEvent']) {  
  5.          putTitle('Details for event: '$event['summary']);  
  6.          putBlock('This event has status ' . $event['status']);  
  7.          putBlock('It was created at ' .  
  8.                date('Y-m-d H:m'strtotime($event['created'])) .  
  9.                ' and last updated at ' .  
  10.                date('Y-m-d H:m'strtotime($event['updated'])) . '.');  
  11.          putBlock('For this event you have to <strong>' . $event['summary'] . '</strong>.');  
  12.       }  
  13. }  

我们可以明显看到,无论if声明中的内容如何、其代码都属于表示代码,而余下的部分则属于业务逻辑。与其利用一个庞大的函数处理所有事务,我们更倾向于将其拆分为多个不同函数:

  1. function printEventDetails() {  
  2.    global $client;  
  3.    foreach (retrieveEvents($_GET['calendarId']) as $event)  
  4.       if (isCurrentEvent($event))  
  5.          putEvent($event);  
  6. }  
  7.    
  8. function isCurrentEvent($event) {  
  9.    return $event['id'] == $_GET['showThisEvent'];  
  10. }  

分离工作完成后,业务逻辑就变得简单易懂了。我们甚至提取了一个小型方法来检测该事件是否就是当前事件。所有表示代码现在都由名为putEvent($event)函数负责,且被保存在functions_display.php文件当中:

  1. function putEvent($event) {  
  2.    putTitle('Details for event: ' . $event['summary']);  
  3.    putBlock('This event has status ' . $event['status']);  
  4.    putBlock('It was created at ' .  
  5.          date('Y-m-d H:m'strtotime($event['created'])) .  
  6.          ' and last updated at ' .  
  7.          date('Y-m-d H:m'strtotime($event['updated'])) . '.');  
  8.    putBlock('For this event you have to <strong>' . $event['summary'] . '</strong>.');  
  9. }  

尽管该方法只负责显示信息,但其功能仍需在对$event结构非常了解的前提下方能实现。不过对于我们的简单实例来说,这已经足够了。对于其余方法,大家可以通过类似的方式进行分离。

清除过长的if-else声明

目前代码整理工作还剩下最后一步,也就是存在于doUserAction()函数中的过长if-else声明,其作用是决定每项行为的实际处理方式。在元编程方面(通过引用来调用函数),PHP具备相当出色的灵活性。这种特性使我们能够将$_GET变量的值与函数名称关联起来。如此一来,我们可以在$_GET变量中引入单独的action参数,并将该值作为函数名称。

  1. function doUserAction() {  
  2.    putMenu();  
  3.    if (!isset($_GET['action'])) return;  
  4.       $_GET['action']();  
  5. }  

基于这种方式,我们生成的菜单将如下所示:

  1. function putMenu() {  
  2.    putLink('?action=putHome''Home');  
  3.    putLink('?action=printCalendars''Show Calendars');  
  4.    putLink('?logout''Log Out');  
  5.    print('<br><br>');  
  6. }  

如大家所见,经过重新整理之后,代码已经呈现出面向对象式设计的特性。虽然目前我们还不清楚其面向的是何种对象、会执行哪些确切行为,但其特征已经初露端倪。

我们已经让来自业务逻辑的数据类型成为表示的决定性因素,其效果与我们在文首介绍环节中谈到的依赖倒置机制比较类似。控制流的方向仍然是从业务逻辑指向表示,但源代码依赖性则与之相反。从这一点上看,我认为整套机制更像是一种双向依赖体系。

设计倾向上的面向对象化还体现在另一个方面,即我们几乎没有涉及到元编程。我们可以调用一个方法,但却对其一无所知。该方法可以拥有任何内容,且过程与处理低级多态性非常相近。

依赖性分析

对于当前代码我们可以绘制出一份关系图,内容如下所示。通过这幅关系图,我们可以看到应用程序运行流程的前几个步骤。当然,把整套流程都画下来就太过复杂了。


蓝色线条代表程序调用。如大家所见,这些线条与始终指向同一个方向。图中的绿色线条则表示间接调用,可以看到所有间接调用都要经过doUserAction()函数。这两种线条代表控制流,显然控制流的走向基本不变。

红色线条则引入了完全不同的概念,它们代表着最初的源代码依赖关系。之所以说“最初”,是因为随着应用的运行其指向将变得愈发复杂、难以把握。putMenu()方法中包含着被特定关系所调用的函数的名称。这是一种依赖关系,同时也是适用于所有其它关系创建方法的基本规则。它们的具体关系取决于其它函数的行为。

上图中我们还能看到另一种依赖关系,即对数据的依赖。我前面曾经提到过$calendar与$event,输出函数需要清楚了解这些数组的内部结构才能实现既定功能。

完成了以上内容之后,我们已经做好充分准备、可以迎来本篇教程中的最后一项挑战。


酷毙
1

雷人

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部