8.编写代码类

  每个分离的函数可以执行一个明确的任务。任务越简单,编写与测试这个函数就越简单,当然也不要将这个函数分得太小——若将程序分成太多的小个体,读起来就会很困难。

  使用继承可以重载操作。我们可以替换成一个大的Display()函数,但是改变整个页面的显示方式几乎是不可能的。将显示功能分成几个独立的任务则更好,这样我们可以只需重载需要改变的部分。

  如下所示的page类提供了简单灵活的方法来创建页面:

<?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"; //metatags便于搜索引擎对其检索
public $buttons = array("Home" => "home.php",
"Contact" => "contact.php",
"Services" => "services.php",
"Site Map" => "map.php"
); //使用一个数组来保存按钮的文本标签以及该按钮指向的URL // 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 width="100%" cellpadding="12"
cellspacing="0" border="0">
<tr bgcolor ="black">
<td align ="left"><img src = "logo.gif" /></td>
<td>
<h1>TLA Consulting Pty Ltd</h1>
</td>
<td align ="right"><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 width="100%" bgcolor="black" cellpadding="12" border="0">
<tr>
<td>
<p class="foot">&copy; TLA Consulting Pty Ltd.</p>
<p class="foot">Please see our <a href ="">legal
information page</a></p>
</td>
</tr>
</table>
<?php
}
}
?>

  请注意函数DisplayStyles()、DisplayHeader()和DisplayFooter()需要显示没有经过PHP处理的大量静态HTML。因此,我们简单地使用了PHP结束标记(?>)、输入HTML,然后再在函数体内部使用一个PHP打开标记(<?php)。

操作IsURLCurrentPage()将判断按钮URL是否指向当前页。

  这里,我们使用了字符串函数strpos(),它可以查看给定的URL是否包含在服务器设置的变量中。strpos($__SERVER[‘PHP_SELF’], $url)语句将返回一个数字(如果$url中的字符串包含在全局变量$_SERVER[‘PHP_SELF’])或者false(如果没有包含在全局变量中)。

  首页使用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类里继承大多数功能,但是必须重载需要修改的部分。

  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();
?>

  通过PHP类创建页面的好处是显而易见的,通过用类完成了大部分工作,在创建页面的时候,我们就可以做更少的工作。在更新页面的时候,只要简单地更新类即可。通过继承,我们还可从最初的类派生出不同版本的类而不会破坏这些优势。

  不过,用脚本创建网页要求更多计算机处理器的处理操作,应该尽量使用静态HTML网页,或者尽可能缓存脚本输出,从而减少在服务器上的载入操作。

9.PHP面向对象的高级功能

  9.1 使用Pre-Class常量

  可以在不需要初始化该类的情况下使用该类中的常量

class Math {

    const pi = 3.14159; //定义常量

}

echo Math::pi;

  可以通过使用::操作符指定常量所属的类来访问Per-Class常量。

  9.2 实现静态方法

  和Pre-Class常量的思想一样,可以在未初始化类的情况下直接调用这个方法,不过,在这个静态方法中,不允许使用 this 关键字,因为可能会没有可以引用的对象。

class Math {

    static function squared($input) {

        return $input * $input;

    }

}

echo Math::squared(8);

  9.3 检查类的类型和类型提示

  instanceof 关键字允许检查一个对象的类型。可以检查一个对象是否是特定类的实例,是否是从某个类继承过来或者是否实现了某个接口。

  另外,类型检查等价于 instanceof 的作用。

function check_hint(B $someclass){

  // ...

}

  以上示例将要求$someclass必须是类B的实例。如果按如下方式传入了类A的一个实例:

check_hint($a);

  将产生如下所示的致命错误:

Fatal error: Argument 1 must be an instance of B

  9.4 延迟静态绑定

  PHP 5.3版本引入了延迟静态绑定(late static binding)的概念,该特性允许在一个静态继承的上下文对一个被调用类的引用。父类可以使用子类重载的静态方法。如下所示的是PHP手册提供的延迟静态绑定示例:

<?php

class A{

  public static function who(){

    echo __CLASS__;

  }

  public static function test(){

    static::who(); // Here comes Late Static Bindings

  }

}

class B extends A{

  public static function who(){

    echo __CLASS__;

  }

}

B::test();

?>

  通俗的说,就是B通过继承走的A里的test(),然后通过静态延迟走的B里重载的who()。

  无论类是否被重载,允许在运行时调用类的引用将为你的类提供更多的功能。

  9.5 克隆对象

  PHP提供了 clone 关键字,该关键字允许复制一个已有的对象。

$c = clone $b;

  将创建与对象 $b 具有相同类的副本,而且具有相同的属性值。

  当然,可以自己在类中重新定义 __clone 函数,来控制克隆的过程。

  9.6 使用抽象类

  PHP提供了抽象类。这些类不能被实例化,同样类方法也没有实现,只是提供类方法的声明,没有具体实现。

abstract operationX($param1, $param2);

  包含抽象方法的任何类自身必须是抽象的。

  抽象方法和抽象类主要用于复杂的类层次关系中,该层次关系需要确保每一个子类都包含并重载了某些特性的方法,这也可以通过接口来实现。

  9.7 使用__call()重载方法

  在PHP中,__call()方法用来实现方法的重载。

<?php

class overload {

    public function displayArray($array) {

        foreach($array as $print) {

            echo $print;

            echo "<br />";

        }

    }

    public function displayScalar($scalar) {

        echo $scalar;

        echo "<br />";

    }

    public function __call($method, $p) {

        if ($method == "display") {

            if (is_object($p[0])) {

                $this->displayObject($p[0]);

            } else if (is_array($p[0])) {

                $this->displayArray($p[0]);

            } else {

                $this->displayScalar($p[0]);

            }

        }

    }

}

$ov = new overload;

$ov->display(array(1, 2, 3));

$ov->display('cat');

 ?>

  __call()方法必须带有两个参数。第一个包含了被调用的方法名称,而第二个参数包含了传递给该方法的参数数组。

  使用 __call 方法,不需要实现任何 display() 方法。

  9.8 使用__autoload()方法

  __autoload()函数将在实例化一个还没有被声明的类时自动调用。

  __autoload()方法的主要用途是尝试包含或请求任何用来初始化所需类的文件。

  9.9 实现迭代器和迭代

  可以使用foreach()方法通过循环方式取出一个对象的所有属性,就像数组方式一样。

<?php

class myClass{

  public $a = "5";

  public $b = "7";

  public $c = "9";

}

$x = new myClass;

foreach($x as $attribute){

  echo $attribute."<br />";

}

?>

  如果需要一些更加复杂的行为,可以实现一个iterator(迭代器)。要实现一个迭代器,必须将要迭代的类实现IteratorAggregare接口,并且定义一个能够返回该迭代类实例的getIterator方法。这个类必须实现Iterator接口,该接口提供了一系列必须实现的方法。

  迭代器和迭代的示例基类:

<?php
class ObjectIterator implements Iterator { //迭代器 这个类实现了interator接口 private $obj;
private $count;
private $currentIndex; function __construct($obj)
{
$this->obj = $obj;
$this->count = count($this->obj->data);
}
function rewind()
{
$this->currentIndex = 0;
}
function valid()
{
return $this->currentIndex < $this->count;
}
function key()
{
return $this->currentIndex;
}
function current()
{
return $this->obj->data[$this->currentIndex];
}
function next()
{
$this->currentIndex++;
}
} class Object implements IteratorAggregate //接口
{
public $data = array(); function __construct($in)
{
$this->data = $in;
} function getIterator()
{
return new ObjectIterator($this); //返回迭代示例的方法
}
} $myObject = new Object(array(2, 4, 6, 8, 10)); $myIterator = $myObject->getIterator();
for($myIterator->rewind(); $myIterator->valid(); $myIterator->next())
{
$key = $myIterator->key();
$value = $myIterator->current();
echo $key." => ".$value."<br />";
} ?>

  ObjectIterator类具有Iterator接口所要求的一系列函数:

    · 构造函数并不是必需的,但是很明显,它是设置将要迭代的项数和当前数据项链接的地方。

    · rewind()函数将内部数据指针设置回数据开始处。

    · valid()函数将判断数据指针的当前位置是否还存在更多数据。

    · key()函数将返回数据指针的值。

    · value()函数将返回保存在当前数据指针的值。

    · next()函数在数据中移动数据指针的位置。

  像这样使用Iterator类的原因就是即使潜在的实现发生了变化,数据的接口还是不会发生变化。

  9.10 将类转换成字符串

  __toString()函数的所有返回内容都将被echo语句打印。

<?php

$p = new Printable;

echo $p;

class Printable{

  public $testone;

  public $testtwo;

  public function __toString(){

    return(var_export($this, TRUE));

  }

}

?>

  var_export()函数打印出了类中的所有属性值。

  9.11 使用Reflection(反射)API

  PHP的面向对象引擎还包括反射API。反射是通过访问已有类和对象来找到类和对象的结构和内容的能力。

  显示关于Page类的信息:

<?php

require_once("page.inc");

$class = new ReflectionClass("Page");

echo "<pre>".$class."</pre>";

?>

  这里使用了Reflection类的__toString()方法来打印这个数据。注意,<pre>标记位于不同的行上,不要与__toString()方法混淆。

整理自《PHP和MySQL Web开发》

从零开始攻略PHP(8)——面向对象(下)的更多相关文章

  1. 从零开始攻略PHP(9)——错误和异常处理

    1.Exception类 这个类是PHP为异常处理提供的内置类.构造函数的两个参数分别是错误消息和错误代码. 除了构造函数之外,该类还提供了如下的内置方法: · getCode() 返回传递给构造函数 ...

  2. 从零开始攻略PHP(7)——面向对象(上)

    1.理解面向对象的概念 面向对象软件的一个重要优点是支持和鼓励封装的能力.封装也叫数据隐藏. 在面向对象的软件中,对象是一个被保存数据和操作这些数据的操作方法的唯一.可标识的集合. 对象可以按类进行分 ...

  3. 从零开始攻略PHP(5)——字符串操作与POSIX正则

    一.字符串操作 1.字符串的格式化 1.1 干掉空格 trim()函数可以除去字符串开始位置和结束位置的空格,并将结果字符串返回. ltrim()函数可以除去字符串开始位置的空格. rtrim()函数 ...

  4. 从零开始攻略PHP(4)——数组的使用

    1.数组的概念 数组就是一个用来存储一系列变量值的命名区域. 每个数组元素有一个相关的索引(也成为关键字),它可以用来访问元素. PHP允许间隔性地使用数字或字符串作为数组的索引. 2.数字索引数组 ...

  5. 从零开始攻略PHP(6)——代码重用与函数编写的一些注意事项

    一个新的项目是这样创建的:它将已有的可重新利用的组件进行组合,并将新的开发难度降低到最小. 代码重用的好处:降低成本.提升可靠性和一致性. 1.使用require()和include()函数 使用一条 ...

  6. Windows下LATEX排版论文攻略—CTeX、JabRef使用介绍

    Windows下LATEX排版论文攻略—CTeX.JabRef使用介绍 一.工具介绍 TeX是一个很好排版工具,在学术界十分流行,特别是数学.物理学和计算机科学界. CTeX是TeX中的一个版本,指的 ...

  7. linux下安装apache与php;Apache+PHP+MySQL配置攻略

    1.apache   在如下页面下载apache的for Linux 的源码包    http://www.apache.org/dist/httpd/;   存至/home/xx目录,xx是自建文件 ...

  8. Python环境下NIPIR(ICTCLAS2014)中文分词系统使用攻略

    一.安装 官方链接:http://pynlpir.readthedocs.org/en/latest/installation.html 官方网页中介绍了几种安装方法,大家根据个人需要,自行参考!我采 ...

  9. fiddler Android下https抓包全攻略

    fiddler Android下https抓包全攻略 fiddler的http.https的抓包功能非常强大,可非常便捷得对包进行断点跟踪和回放,但是普通的配置对于像招商银行.支付宝.陌陌这样的APP ...

随机推荐

  1. 关于C语言读取多行数据的问题

    我有如下数据格式3360  2001     5   1750.5   1246.5  22.5  n    1775=1177-1316:13360  2001     5   1750.5   1 ...

  2. java继承覆盖总结

      Java基础(1)  版权声明:本文为博主原创文章,未经博主允许不得转载. java的继承与覆盖基本是java笔试中常出的题,也比较绕,我这里对java的继承覆盖做一个总结1.构造函数:      ...

  3. ①spirngMVC框架运行原理图

  4. AppDelegate

    一.基础知识 1) main.m指定了程序的入口点 UIApplicationMain(argc, argv,nil,NSStringFromClass([StartingPointAppDelega ...

  5. Mongo中的数据类型

    一.null null用于表示空值或者不存在的字段 {"X" : null} 二.布尔型 布尔类型有两个值true和false {"x" : true} 三.数 ...

  6. 回退(pop&present)到根页面(根控制器)的方法,很不错~

    http://blog.csdn.net/assholeu/article/details/45897035

  7. 怎么用sql语句查询一个数据库有多少张表

    今天在技术群中闲谈时忽然聊到一个问题,那就是当一个数据库中有多张表时怎么快速的获取到表的个数,从而给问询者一个准确的回答. 大家或许会说,这个问题和我们的数据库操作没有太大关系或者不是很挂钩,所以没意 ...

  8. [LeetCode] Simplify Path(可以不用看)

    Given an absolute path for a file (Unix-style), simplify it. For example, path = "/home/", ...

  9. Java实验三报告

    一.  实验内容 (一)敏捷开发与XP 摘要:一项实践在XP环境中成功使用的依据通过XP的法则呈现,包括:快速反馈.假设简单性.递增更改.提倡更改.优质工作.XP软件开发的基石是XP的活动,包括:编码 ...

  10. ECSHOP不同商品分类调用不同模板

    1.在ecs_category 表 添加 template 字段 可以在后台运行sql语句:alter table `ecs_category` Add column template text NO ...