PHP面向对象编程的7个好习惯(1)_PHP教程
但是,没有面向对象的语言构造,程序员仍然可以把 OO 特性引入到 PHP 代码中。这样做有点困难并且会使代码难于阅读,因为它是混合范例(含有伪 OO 设计的过程语言)。使用 PHP 代码中的OO构造 — 例如能够定义和使用类、能够构建使用继承的类之间的关系以及能够定义接口 — 可以更轻松地构建符合优秀 OO 实践的代码。
虽然没有过多模块化的纯过程设计运行得很好,但是 OO 设计的优点表现在维护上。由于典型应用程序的大部分生命周期都花费在维护上,因此代码维护是应用程序生命周期的重要部分。并且在开发过程中代码维护很容易被遗忘。如果在应用程序开发和部署方面存在竞争,那么长期可维护性可能被放在比较次要的地位。
模块化 — 优秀 OO 设计的主要特性之一 — 可以帮助完成这样的维护。模块化将帮助封装更改,这样可以随着时间的推移更轻松地扩展和修改应用程序。
总的来说,虽然构建 OO 软件的习惯不止 7 个,但是遵循这里的 7 个习惯可以使代码符合基本 OO 设计标准。它们将为您提供更牢固的基础,在此基础之上建立更多 OO 习惯并构建可轻松维护与扩展的软件。这些习惯针对模块化的几个主要特性。有关独立于语言的 OO 设计优点的更多信息,请参阅 参考资料。
7 个优秀PHP OO 习惯包括:
◆保持谦虚。
◆做个好邻居。
◆避免看到美杜莎。
◆利用最弱的链接。
◆您是橡皮;我是胶水。
◆限制传播。
◆考虑使用模式。
保持谦虚
保持谦虚指避免在类实现和函数实现中暴露自己。隐藏您的信息是一项基本习惯。如果不能养成隐藏实现细节的习惯,那么将很难养成任何其他习惯。信息隐藏也称为封装。
直接公开公共字段是一个坏习惯的原因有很多,最重要的原因是让您在实现更改中没有应有的选择。使用 OO 概念隔离更改,而封装在确保所作更改在本质上不是病毒性(viral)更改方面扮演不可或缺的角色。病毒性 更改是开始时很小的更改 — 如将保存三个元素的数组更改为一个只包含两个元素的数组。突然,您发现需要更改越来越多的代码以适应本应十分微不足道的更改。
开始隐藏信息的一种简单方法是保持字段私有并且用公共访问方法公开这些字段,就像家中的窗户一样。并没有让整面墙都朝外部开放,而只打开一两扇窗户(我将在 “好习惯:使用公共访问方法” 中介绍访问方法的更多信息)。
除了允许您的实现隐藏在更改之后外,使用公共访问方法而非直接公开字段将允许您在基本实现的基础上进行构建,方法为覆盖访问方法的实现以执行略微不同于父方法的行为。它还允许您构建一个抽象实现,从而使实际实现委托给覆盖基本实现的类。
坏习惯:公开公共字段
在清单 1 的坏代码示例中,Person 对象的字段被直接公开为公共字段而非使用访问方法。虽然此行为十分诱人,尤其对于轻量级数据对象来说更是如此,但是它将对您提出限制。
◆清单 1. 公开公共字段的坏习惯
<?phpclass Person{ public $prefix; public $givenName; public $familyName; public $suffix;}$person = new Person();$person->prefix = "Mr.";$person->givenName = "John";echo ($person->prefix);echo($person->givenName);?> |
如果对象有任何更改,则使用该对象的所有代码也都需要更改。例如,如果某人的教名、姓氏和其他名字被封装到 PersonName 对象中,则需要修改所有代码以适应更改。
好习惯:使用公共访问方法
通过使用优秀的 OO 习惯(参见清单 2),同一个对象现在拥有私有字段而非公共字段,并且通过称为访问方法 的 get 和 set 公共方法谨慎地向外界公开私有字段。这些访问方法现在提供了一种从 PHP 类中获取信息的公共方法,这样在实现发生更改时,更改使用类的所有代码的需求很可能变小。
◆清单 2. 使用公共访问方法的好习惯
<?phpclass Person{ private $prefix;private $givenName; private $familyName; private $suffix;public function setPrefix($prefix) {$this->prefix = $prefix; }public function getPrefix() { return $this->prefix;} public function setGivenName($gn){$this->givenName = $gn;} public function getGivenName() {return $this->givenName;} public function setFamilyName($fn){$this->familyName = $fn;} public function getFamilyName() {return $this->familyName;} public function setSuffix($suffix){$this->suffix = $suffix;} public function getSuffix() { return $suffix;} }$person = new Person(); $person->setPrefix("Mr.");$person->setGivenName("John");echo ($person->getPrefix());echo($person->getGivenName());?> |
乍看之下,这段代码可能会完成大量工作,并且实际上可能更多是在前端的工作。但是,通常,使用优秀的 OO 习惯从长远来看十分划算,因为将极大地巩固未来更改。
在清单 3 中所示的代码版本中,我已经更改了内部实现以使用名称部件的关联数组。比较理想的情况是,我希望拥有错误处理并且更仔细地检查元素是否存在,但是本例的目的在于展示使用我的类的代码无需更改的程度 — 代码并没有察觉到类发生更改。记住采用 OO 习惯的原因是要谨慎封装更改,这样代码将更具有可扩展性并且更容易维护。
1