在确定了代码的最终运行结果的式样,以及所需的一些特性后,应该开始考虑如何实现它们。在本章的后续内容中,我们将介绍大型项目的设计和管理。现在,我们先集中介绍编写面向对象的PHP脚本部分。
类需要一个逻辑名称。因为它代表一个页面,所以称之为Page。要声明这个Page类,可以使用如下所示的代码:
class Page
{
}
Page类需要一些属性,需要将那些可能要在页与页之间不断修改的元素设置为类的属性。
页面的主要内容,也就是HTML标签和文本的组合,我们将其命名为$content。可以在类定义中使用如下所示的代码来声明它:
public$content;
也可以设置属性来保存页面的标题。我们可能会对其进行修改,从而确保能够清楚地显示访问者浏览的特定页面。为了不让页面标题为空,可以使用如下所示的声明来提供一个默认标题:
public$title=/"TLA Consulting Pty Ltd/";
大多数商业网站的网页都包含了metatags,这样便于搜索引擎对其检索。为了使其更实用,不同页面的metatags应该尽可能不同。同样,我们可以提供一个默认值,如下所示:
public$keywords=/"TLA Consulting,Three Letter Abbreviation,
some of my best friends are search engines/";
图5-2(请参阅第5章)显示的原始页面上的导航条应该在每一页面都应该相同,这样可以避免浏览者混淆。但为了使它们修改起来更加容易,我们也赋给它们一个属性。由于按钮的数量在不同页面可能会有所不同,因此需要使用一个数组,来保存按钮的文本标签以及该按钮指向的URL:
public$buttons=array(/"Home/"=>/"home.php/",
/"Contact/"=>/"contact.php/",
/"Services/"=>/"services.php/",
/"Site Map/"=>/"map.php/"
);
要提供这些功能,类也需要一些操作。可以从定义访问函数来设置和获得已定义的变量值开始。这些函数定义如下所示:
public function__set($name,$value)
{
$this->$name=$value;
}
__set函数不包含错误检查(从简化的角度出发),但是该功能可随后轻松增加。因为你从类的外部请求这些值是不可能的,所以在此可选择不提供__get函数。
该类的主要功能是显示HTML页面,因此我们需要一个显示函数。该函数名称为Display,其代码如下所示:
public function Display
{
echo/"<html>n<head>n/";
$this->DisplayTitle;
$this->DisplayKeywords;
$this->DisplayStyles;
echo/"</head>n<body>n/";
$this->DisplayHeader;
$this->DisplayMenu($this->buttons);
echo$this->content;
$this->DisplayFooter;
echo/"</body>n</html>n/";}
该函数包含了几个简单的、用来显示HTML代码的回显语句,但主要包含对类中其他函数的调用。从它们的名字可以猜出,这些被调用的函数显示页面各个部分。
像这样将各个函数分成多块不是必需的。所有这些分离的函数可以简单地合成一个大函数。我们将它们分开是有一些原因的。
每个分离的函数可以执行一个明确的任务。任务越简单,编写与测试这个函数就越简单。当然也不要将这个函数分得太小——若将程序分成太多的小个体,读起来就会很困难。
使用继承可以重载操作。我们可以替换成一个大的Display函数,但是改变整个页面的显示方式几乎是不可能的。将显示功能分成几个独立的任务则更好,这样我们可以只需重载需要改变的部分。
Display函数调用了DisplayTitle、DisplayKeywords、DisplayStyles、DisplayHeader、DisplayMenu和DisplayFooter。这就意味着需要定义这些操作。我们可以按照这个逻辑顺序编写这些函数或操作,而且可以在具体代码之前调用它们。在许多其他语言中,只有在编写了函数或操作之后才能调用它们。大多数操作都相当简单,只需显示一些HTML,也可能要显示一些属性的内容。
程序清单6-1完整地显示了该类,我们将它保存为page.inc,它可以包含或被包含于其他文件。
程序清单6-1 page.inc——page类提供了简单灵活的方法来创建TLA页面
<?php
class Page
{
//class Page/'s attributes
public$content;
public$title=/"TLA Consulting Pty Ltd/";
public$keywords=/"TLA Consulting,Three Letter Abbreviation,
some of my best friends are search engines/";
public$buttons=array(/"Home/"=>/"home.php/",
/"Contact/"=>/"contact.php/",
/"Services/"=>/"services.php/",
/"Site Map/"=>/"map.php/"
);
//class Page/'s operations
public function__set($name,$value)
{
$this->$name=$value;
}
public function Display
{
echo/"<html>n<head>n/";
$this->DisplayTitle;
$this->DisplayKeywords;
$this->DisplayStyles;
echo/"</head>n<body>n/";
$this->DisplayHeader;
$this->DisplayMenu($this->buttons);
echo$this->content;
$this->DisplayFooter;
echo/"</body>n</html>n/";
}
public function DisplayTitle
{
echo/"<title>/".$this->title./"</title>/";
}
public function DisplayKeywords
{
echo/"<meta name=/"keywords/"
content=/"/".$this->keywords./"/"/>/";
}
public function DisplayStyles
{
?>
<style>
h1{
color:white;font-size:24pt;text-align:center;
font-family:arial,sans-serif
}
.menu{
color:white;font-size:12pt;text-align:center;
font-family:arial,sans-serif;font-weight:bold
}
td{
background:black
}
p{
color:black;font-size:12pt;text-align:justify;
font-family:arial,sans-serif
}
p.foot{
color:white;font-size:9pt;text-align:center;
font-family:arial,sans-serif;font-weight:bold
}
a:link,a:visited,a:active{
color:white
}
</style>
<?php
}
public function DisplayHeader
{
?>
<table cellpadding=/"12/"
cellspacing=/"0/"border=/"0/">
<tr bgcolor=/"black/">
<td ><img src=/"logo.gif/"/></td>
<td>
<h1>TLA Consulting Pty Ltd</h1>
</td>
<td ><img src=/"logo.gif/"/></td>
</tr>
</table>
<?php
}
public function DisplayMenu($buttons)
{
echo/"<table width=/"100%/"bgcolor=/"white/"
cellpadding=/"4/"cellspacing=/"4/">n/";
echo/"<tr>n/";
//calculate button size
$width=100/count($buttons);
while(list($name,$url)=each($buttons)){
$this->DisplayButton($width,$name,$url,
!$this->IsURLCurrentPage($url));
}
echo/"</tr>n/";
echo/"</table>n/";
}
public function IsURLCurrentPage($url)
{
if(strpos($_SERVER[/'PHP_SELF/'],$url)==false)
{
return false;
}
else
{
return true;
}
}
public function
DisplayButton($width,$name,$url,$active=true)
{
if($active){
echo/"<td width=/"/".$width./"%/">
<a href=/"/".$url./"/">
<img src=/"s-logo.gif/"alt=/"/".$name./"/"border=/"0/"/></a>
<a href=/"/".$url./"/"><span class=/"menu/">/".$name./"</span></a>
</td>/";
}else{
echo/"<td width=/"/".$width./"%/">
<img src=/"side-logo.gif/">
<span class=/"menu/">/".$name./"</span>
</td>/";
}
}
public function DisplayFooter
{
?>
<table bgcolor=/"black/"cellpadding=/"12/"border=/"0/">
<tr>
<td>
<p>©TLA Consulting Pty Ltd.</p>
<p>Please see our<a href=/"/">legal
information page</a></p>
</td>
</tr>
</table>
<?php
}
}
?>
当阅读这个类的时候,请注意函数DisplayStyles、DisplayHeader和DisplayFooter需要显示没有经过PHP处理的大量静态HTML。因此,我们简单地使用了PHP结束标记(?>)、输入HTML,然后再在函数体内部使用一个PHP打开标记(<?php)。
该类还定义了其他两个操作。操作DisplayButton将输出一个简单的菜单按钮。如果该按钮指向当前所在的页面,将显示一个没有激活的按钮,这时它看起来就有点不同,并且不指向任何页面。这就使得整个页面布局和谐,并且访问者可看出自己的位置。
操作IsURLCurrentPage将判断按钮URL是否指向当前页。如今有许多技术可以实现它。
这里,我们使用了字符串函数strpos,它可以查看给定的URL是否包含在服务器设置的变量中。strpos($__SERVER[/'PHP_SELF/'],$url)语句将返回一个数字(如果$url中的字符串包含在全局变量$_SERVER[/'PHP_SELF/'])或者false(如果没有包含在全局变量中)。
要使用Page类,需要在脚本语言中包含page.inc来调用Display函数。
程序清单6-2中的代码将创建TLA咨询公司的首页,并且产生与第5章的图5-2非常类似的输出。
程序清单6-2中的代码将实现如下功能:
1)使用require语句包含page.inc的内容,page.inc中包含了Page类的定义。
2)创建了Page类的一个实例。该实例称为$homepage。
3)设定内容,包括页面显示的文本和HTML标记(这将间接地调用__set方法)。
4)在对象$homepage中调用操作Display,使页面显示在访问者的浏览器中。
程序清单6-2 home.php——首页使用Page类完成生成页面内容的大部分工作
<?php
require(/"page.inc/");
$homepage=new Page;
$homepage->content=/"<p>Welcome to the home of TLA Consulting.
Please take some time to get to know us.</p>
<p>We specialize in serving your business needs
and hope to hear from you soon.</p>/";
$homepage->Display;
?>
在以上的程序清单中可以看出,如果使用Page类,我们在创建新页面的时候只要做少量工作。通过这种方法使用类意味着所有页面都必须很相似。
如果希望网站的一些地方使用不同的标准页,只要将page.inc复制到名为page2.inc的新文件里,并做一些改变就可以了。这意味着每一次更新或修改page.inc时,要记得对page2.inc进行同样的修改。
一个更好的方法是用继承来创建新类,新类从Page类里继承大多数功能,但是必须重载需要修改的部分。对于TLA网站来说,要求服务页包含另一个导航条。程序清单6-3所示的脚本通过创建一个继承了Page的名为ServicesPage的新类来实现它。我们提供了一个名为$row2buttons的新数组,它包含出现在第二行中的按钮和链接。因为我们希望该类和其他类的大部分风格相同,因此只需要重载许要修改的部分——Display操作。
程序清单6-3 services.php——services页面继承了Page类,但是重载了Display操作,从而改变了其输出结果
<?php
require(/"page.inc/");
class ServicesPage extends Page
{
private$row2buttons=array(
/"Re-engineering/"=>/"reengineering.php/",
/"Standards Compliance/"=>/"standards.php/",
/"Buzzword Compliance/"=>/"buzzword.php/",
/"Mission Statements/"=>/"mission.php/"
);
public function Display
{
echo/"<html>n<head>n/";
$this->DisplayTitle;
$this->DisplayKeywords;
$this->DisplayStyles;
echo/"</head>n<body>n/";
$this->DisplayHeader;
$this->DisplayMenu($this->buttons);
$this->DisplayMenu($this->row2buttons);
echo$this->content;
$this->DisplayFooter;
echo/"</body>n</html>n/";
}
}
$services=new ServicesPage;
$services->content=/"<p>At TLA Consulting,we offer a number
of services.Perhaps the productivity of your employees would
improve if we re-engineered your business.Maybe all your business
needs is a fresh mission statement,or a new batch of
buzzwords.</p>/";
$services->Display;
?>
重载后的函数Display与原函数是非常相似的,但它包含了额外的一行:
$this->DisplayMenu($this->row2buttons);
它可以第二次调用DisplayMenu,再创建一个菜单条。
在类的定义之外,我们创建了类ServicesPage的一个实例。设置我们不希望的默认值,并调用Display。
如图6-2所示,我们创建了新的不同标准页。需要编写的新代码只是那些不同部分的代码。
图 6-2 通过继承创建services页,重用标准页的大部分代码通过PHP类创建页面的好处是显而易见的,通过用类完成了大部分工作,在创建页面的时候,我们就可以做更少的工作。在更新页面的时候,只要简单地更新类即可。通过继承,我们还可从最初的类派生出不版本的类而不会破坏这些优势。
当然,就像现实生活中的事情一样,有所得必有所失,这些优点出现也伴随着一定的代价。用脚本创建网页要求更多计算机处理器的处理操作,因为它并不是简单地从硬盘载入静态HTML页然后再送到浏览器。在一个业务繁忙的网站中,处理速度是很重要的,应该尽量使用静态HTML网页,或者尽可能缓存脚本输出,从而减少在服务器上的载入操作。