您的位置:首页 > 编程语言 > PHP开发

PHP入门学习笔记之—— PHP 类与对象 (中)

2016-04-09 22:35 561 查看
J、特征:

PHP的特征

特征

PHP 5.4.0,PHP实现代码重用的方法称为特征。

特征是一种机制,用于在单继承语言(如PHP代码重用。特征是为了减少单继承的一些限制,支持开发人员重用组方法在几个独立自由类生活在不同的类层次结构。组合的语义特征和类定义的方式,降低了复杂性,并避免与多重继承和mixin的典型问题。

特征类似于一个类,但只是为了组织功能在一个细粒度的和一致的方式。不可能自行实例化特征。这是一个除了传统的继承,使水平组合的行为;也就是说,应用程序的类成员不需要继承。

示例# 1特征的例子

<?php

trait ezcReflectionReturnInfo {

function getReturnType() { /*1*/ }

function getReturnDescription() { /*2*/ }

}

class ezcReflectionMethod extends ReflectionMethod {

use ezcReflectionReturnInfo;

/* ... */

}

class ezcReflectionFunction extends ReflectionFunction {

use ezcReflectionReturnInfo;

/* ... */

}

?>

优先级

从基类继承的成员被插入一个成员的特征。成员的优先顺序是当前类覆盖特征方法,返回覆盖继承的方法。

例2优先顺序的例子

从基类继承的方法覆盖的方法插入MyHelloWorld SayWorld特征。这种行为是相同的MyHelloWorld类中定义的方法。方法从当前类的优先顺序是覆盖特征方法,进而覆盖基类的方法。

<?php

class Base {

public function sayHello() {

echo 'Hello ';

}

}

trait SayWorld {

public function sayHello() {

parent::sayHello();

echo 'World!';

}

}

class MyHelloWorld extends Base {

use SayWorld;

}

$o = new MyHelloWorld();

$o->sayHello();

?>

以上例程会输出:

Hello World!

示例# 3替代优先顺序的例子

<?php

trait HelloWorld {

public function sayHello() {

echo 'Hello World!';

}

}

class TheWorldIsNotEnough {

use HelloWorld;

public function sayHello() {

echo 'Hello Universe!';

}

}

$o = new TheWorldIsNotEnough();

$o->sayHello();

?>

以上例程会输出:

Hello Universe!

多个特征可以插入多个特征清单在使用声明一个类,之间用逗号分隔。

示例# 4多个特征使用

<?php

trait Hello {

public function sayHello() {

echo 'Hello ';

}

}

trait World {

public function sayWorld() {

echo ' World';

}

}

class MyHelloWorld {

use Hello, World;

public function sayExclamationMark() {

echo '!';

}

}

$o = new MyHelloWorld();

$o->sayHello();

$o->sayWorld();

$o->sayExclamationMark();>

?>以上例程会输出:

Hello World!

解决冲突如果两个特征插入一个具有相同名称的方法,产生一个致命错误,如果没有显式地解决冲突。

解决命名冲突之间的特征用于同一个类,与运营商需要使用选择完全冲突的方法之一。

因为这只允许一个排除方法,作为操作符可以用来允许包含在另一个名称的冲突的方法之一。

例# 5解决冲突

在这个例子中,说话使用特征和B,A和B以来矛盾的方法,它定义了使用smallTalk的变异特征B,bigTalk的变异特征。

Aliased_Talker利用作为运营商能够使用B bigTalk实现下一个额外的别名。

<?php

trait A {

public function smallTalk() {

echo 'a';

}

public function bigTalk() {

echo 'A';

}

}

trait B {

public function smallTalk() {

echo 'b';

}

public function bigTalk() {

echo 'B';

}

}

class Talker {

use A, B {

B::smallTalk insteadof A;

A::bigTalk insteadof B;

}

}

class Aliased_Talker {

use A, B {

B::smallTalk insteadof A;

A::bigTalk insteadof B;

B::bigTalk as talk;

}

}

?>改变方法的可见性使用语法,还可以调整方法在展示类的可见性。

例# 6改变方法的可见性

<?php

trait HelloWorld {

public function sayHello() {

echo 'Hello World!';

}

}

// Change visibility of sayHello

class MyClass1 {

use HelloWorld { sayHello as protected; }

}

// Alias method with changed visibility

// sayHello visibility not changed

class MyClass2 {

use HelloWorld { sayHello as private myPrivateHello; }

}

?>由特征特征正如类可以使用特征,其他特征也会。通过使用一个或多个特征在特征定义,它可以部分或完全由成员中定义的其他特征。

示例# 7特征由特征

<?php

trait Hello {

public function sayHello() {

echo 'Hello ';

}

}

trait World {

public function sayWorld() {

echo 'World!';

}

}

trait HelloWorld {

use Hello, World;

}

class MyHelloWorld {

use HelloWorld;

}

$o = new MyHelloWorld();

$o->sayHello();

$o->sayWorld();

?>以上例程会输出:

Hello World!

抽象特质成员特征支持使用抽象方法为了实施需求表现出类。

示例# 8表达需求的抽象方法

<?php

trait Hello {

public function sayHelloWorld() {

echo 'Hello'.$this->getWorld();

}

abstract public function getWorld();

}

class MyHelloWorld {

private $world;

use Hello;

public function getWorld() {

return $this->world;

}

public function setWorld($val) {

$this->world = $val;

}

}

?>静态特征的成员静态变量可以被称为特征方法,但不能定义的特征。然而,特征可以定义静态方法表现出类。

例# 9静态变量

<?php

trait Counter {

public function inc() {

static $c = 0;

$c = $c + 1;

echo "$c ";

}

}

class C1 {

use Counter;

}

class C2 {

use Counter;

}

$o = new C1(); $o->inc(); // echo 1

$p = new C2(); $p->inc(); // echo 1

?>例# 10静态方法

<?php

trait StaticExample {

public static function doSomething() {

return 'Doing something';

}

}

class Example {

use StaticExample;

}

Example::doSomething();

?>属性品质还可以定义属性。

例# 11定义属性

<?php

trait PropertiesTrait {

public $x = 1;

}

class PropertiesExample {

use PropertiesTrait;

}

$example = new PropertiesExample;

$example->x;

?>如果特征定义了一个属性,那么一个类不能定义一个具有相同名称的属性,否则一个错误。这是一个代码,如果类定义兼容(相同的可见性和初始值)或致命错误。

例# 12解决冲突

<?php

trait PropertiesTrait {

public $same = true;

public $different = false;

}

class PropertiesExample {

use PropertiesTrait;

public $same = true; // Strict Standards

public $different = true; // Fatal error

}

?>

K、重载:PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法。我们是通过 魔术方法(magic methods)来实现的。

当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。本节后面将使用 "不可访问成员(inaccessible members)"和"不可访问方法(inaccessible methods)"来称呼这些未定义或不可见的类属性或方法。

所有的重载方法都必须被声明为public。

Note:

这些魔术方法的参数都不能 通过引用传递。

Note:

PHP中的"重载"与其它绝大多数面向对象语言不同。传统的"重载"是用于提供多个同名的 类方法,但各方法的参数类型和个数不同。

更新日志

版本说明5.1.0新增 __isset() 和 __unset()两个魔术方法.5.3.0新增 __callStatic()魔术方法. 可见性未设置为public或未声明为static的时候会产生一个警告

属性重载void __set ( string $name , mixed $value ) mixed __get ( string $name ) bool __isset( string $name ) void __unset ( string $name )在给未定义的变量赋值时,__set() 会被调用。

读取未定义的变量的值时,__get() 会被调用。

当对未定义的变量调用isset() 或 empty()时,__isset() 会被调用。

当对未定义的变量调用unset()时,__unset() 会被调用。

参数$name是指要操作的变量名称。__set() 方法的$value 参数指定了$name变量的值。

属性重载只能在对象中进行。在静态方法中,这些魔术方法将不会被调用。所以这些方法都不能被 声明为static。

Example #1 使用__get, __set, __isset 和 __unset 进行重载

<?php

class MemberTest {

/** 被重载的数据保存在此 */

private $data = array();

/** 重载不能被用在已经定义的属性 */

public $declared = 1;

/** 只有从类外部访问这个属性时,重载才会发生 */

private $hidden = 2;

public function __set($name, $value) {

echo "Setting '$name' to '$value' ";

$this->data[$name] = $value;

}

public function __get($name) {

echo "Getting '$name' ";

if (array_key_exists($name, $this->data)) {

return $this->data[$name];

}

$trace = debug_backtrace();

trigger_error(

'Undefined property via __get(): ' . $name .

' in ' . $trace[0]['file'] .

' on line ' . $trace[0]['line'],

E_USER_NOTICE);

return null;

}

/** PHP 5.1.0之后版本 */

public function __isset($name) {

echo "Is '$name' set? ";

return isset($this->data[$name]);

}

/** PHP 5.1.0之后版本 */

public function __unset($name) {

echo "Unsetting '$name' ";

unset($this->data[$name]);

}

/** 非魔术方法 */

public function getHidden() {

return $this->hidden;

}

}

echo "<pre> ";

$obj = new MemberTest;

$obj->a = 1;

echo $obj->a . " ";

var_dump(isset($obj->a));

unset($obj->a);

var_dump(isset($obj->a));

echo " ";

echo $obj->declared . " ";

echo "Let's experiment with the private property named 'hidden': ";

echo "Privates are visible inside the class, so __get() not used... ";

echo $obj->getHidden() . " ";

echo "Privates not visible outside of class, so __get() is used... ";

echo $obj->hidden . " ";

?>以上例程会输出:

Setting 'a' to '1'

Getting 'a'

1

Is 'a' set?

bool(true)

Unsetting 'a'

Is 'a' set?

bool(false)

1

Let's experiment with the private property named 'hidden':

Privates are visible inside the class, so __get() not used...

2

Privates not visible outside of class, so __get() is used...

Getting 'hidden'

Notice: Undefined property via __get(): hidden in <file> on line 70 in <file> on line 29

方法重载mixed __call ( string $name , array $arguments ) mixed __callStatic ( string $name ,array $arguments )当调用一个不可访问方法(如未定义,或者不可见)时,__call() 会被调用。

当在静态方法中调用一个不可访问方法(如未定义,或者不可见)时,__callStatic() 会被调用。

$name参数是要调用的方法名称。$arguments参数是一个数组,包含着要传递给方法的参数。

Example #2 使用 __call 和 ___callStatic 调用对象中的方法

<?php

class MethodTest {

public function __call($name, $arguments) {

// 注意: $name 区分大小写

echo "Calling object method '$name' "

. implode(', ', $arguments). " ";

}

/** PHP 5.3.0之后版本 */

public static function __callStatic($name, $arguments) {

// Note: value of $name is case sensitive.

echo "Calling static method '$name' "

. implode(', ', $arguments). " ";

}

}

$obj = new MethodTest;

$obj->runTest('in object context');

MethodTest::runTest('in static context'); // PHP 5.3.0之后版本

?>以上例程会输出:

Calling object method 'runTest' in object context

Calling static method 'runTest' in static context

L、对象迭代:PHP5提供了一种迭代(iteration)对象的功能,就像使用数组那样,可以通过foreach 来遍历对象中的属性。

默认情况下,在外部迭代只能得到外部可见的属性的值。

Example #1 简单的对象迭代

<?php

class MyClass

{

public $var1 = 'value 1';

public $var2 = 'value 2';

public $var3 = 'value 3';

protected $protected = 'protected var';

private $private = 'private var';

function iterateVisible() {

echo "MyClass::iterateVisible: ";

foreach($this as $key => $value) {

print "$key => $value ";

}

}

}

$class = new MyClass();

foreach($class as $key => $value) {

print "$key => $value ";

}

echo " ";

$class->iterateVisible();

?>

以上例程会输出:

var1 => value 1

var2 => value 2

var3 => value 3

MyClass::iterateVisible:

var1 => value 1

var2 => value 2

var3 => value 3

protected => protected var

private => private var

Iterator接口来实现迭代. 使用Iterator接口可以让对象自行决定如何迭代自已。

Example #2 实现Iterator接口的迭代

<?php

class MyIterator implements Iterator

{

private $var = array();

public function __construct($array)

{

if (is_array($array)) {

$this->var = $array;

}

}

public function rewind() {

echo "rewinding ";

reset($this->var);

}

public function current() {

$var = current($this->var);

echo "current: $var ";

return $var;

}

public function key() {

$var = key($this->var);

echo "key: $var ";

return $var;

}

public function next() {

$var = next($this->var);

echo "next: $var ";

return $var;

}

public function valid() {

$var = $this->current() !== false;

echo "valid: {$var} ";

return $var;

}

}

$values = array(1,2,3);

$it = new MyIterator($values);

foreach ($it as $a => $b) {

print "$a: $b ";

}

?>以上例程会输出:

rewinding

current: 1

valid: 1

current: 1

key: 0

0: 1

next: 2

current: 2

valid: 1

current: 2

key: 1

1: 2

next: 3

current: 3

valid: 1

current: 3

key: 2

2: 3

next:

current:

valid:

让类实现IteratorAggregate接口,这样你的类就不用强制性地实现 Iterator接口中的所有方法。

Example #3 通过IteratorAggregate来实现对象迭代

<?php

class MyCollection implements IteratorAggregate

{

private $items = array();

private $count = 0;

// Required definition of interface IteratorAggregate

public function getIterator() {

return new MyIterator($this->items);

}

public function add($value) {

$this->items[$this->count++] = $value;

}

}

$coll = new MyCollection();

$coll->add('value 1');

$coll->add('value 2');

$coll->add('value 3');

foreach ($coll as $key => $val) {

echo "key/value: [$key -> $val] ";

}

?>

以上例程会输出:

rewinding

current: value 1

valid: 1

current: value 1

key: 0

key/value: [0 -> value 1]

next: value 2

current: value 2

valid: 1

current: value 2

key: 1

key/value: [1 -> value 2]

next: value 3

current: value 3

valid: 1

current: value 3

key: 2

key/value: [2 -> value 3]

next:

current:

valid:

M、PHP 设计模式 :使用设计模式是促进最佳实践和良好设计的好办法。

设计模式可以提供针对常见的编程问题的灵活的解决方案。

工厂模式(Factory)允许你在代码执行时实例化对象。它之所以被称为工厂模式是因为它负责“生产”对象。工厂方法的参数是 你要生成的对象对应的类名称。

Example #1 调用工厂方法(带参数)

<?php

class Example

{

// The parameterized factory method

public static function factory($type)

{

if (include_once 'Drivers/' . $type . '.php') {

$classname = 'Driver_' . $type;

return new $classname;

} else {

throw new Exception ('Driver not found');

}

}

}

?>按上面的方式可以动态加载drivers。如果Example类是一个数据库抽象类,那么 可以这样来生成MySQL和 SQLite驱动对象:

<?php

// Load a MySQL Driver

$mysql = Example::factory('MySQL');

// Load a SQLite Driver

$sqlite = Example::factory('SQLite');

?>

单例模式(Singleton)用于为一个类生成一个唯一的对象。最常用的地方是数据库连接。 使用单例模式生成一个对象后,该对象可以被其它众多对象所使用。

Example #2 单例模式

<?php

class Example

{

// 保存类实例在此属性中

private static $instance;

// 构造方法声明为private,防止直接创建对象

private function __construct()

{

echo 'I am constructed';

}

// singleton 方法

public static function singleton()

{

if (!isset(self::$instance)) {

$c = __CLASS__;

self::$instance = new $c;

}

return self::$instance;

}

// Example类中的普通方法

public function bark()

{

echo 'Woof!';

}

// 阻止用户复制对象实例

public function __clone()

{

trigger_error('Clone is not allowed.', E_USER_ERROR);

}

}

?>这样我们可以得到一个独一无二的Example类的对象。

<?php

// 这个写法会出错,因为构造方法被声明为private

$test = new Example;

// 下面将得到Example类的单例对象

$test = Example::singleton();

$test->bark();

// 复制对象将导致一个E_USER_ERROR.

$test_clone = clone $test;

?>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: