2006/02/21

learn:php学习笔记,类与对象(PHP 5)

atags:php,php5,object,class,学习笔记,类,对象
PHP 5 引入了新的对象模型(Object Model)。完全重写了 PHP 处理对象的方式,允许更佳性能和更多特性。
基本概念
每个类的定义都以关键字 class 开头,后面跟着类名,可以是任何非 PHP 保留字的名字。后面跟着一对花括号,里面包含有类成员和方法的定义。伪变量 $this 可以在当一个方法在对象内部调用时使用。$this 是一个到调用对象(通常是方法所属于的对象,但也可以是另一个对象,如果该方法是从第二个对象内 静态 调用的话)的引用。
<?php
class
A
{
function
foo
()
{
if (isset(
$this
)) {
echo
'$this is defined ('
;
echo
get_class($this
);
echo
")\n"
;
} else {
echo
"\$this is not defined.\n"
;
}
}
}

class
B
{
function
bar
()
{
A ::foo
();
}
}

$a = new A
();
$a ->foo
();
A ::foo
();
$b = new B
();
$b -> bar
();
B :: bar
();
?>
output:
$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.
简单的类定义
class SimpleClass
{
// 成员声明
public $var = 'a default value'
;

// 方法声明
public function displayVar
() {
echo
$this ->var
;
}
}
new
要创建一个对象的实例,必须创建一个新对象并将其赋给一个变量。当创建新对象时该对象总是被赋值,除非该对象定义了构造函数并且在出错时抛出了一个 异常

<?php
$instance
= new SimpleClass
()
?>

当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用克隆给一个已创建的对象建立一个新实例。=用于克隆除非使用&来标示传递引用
extends
一个类可以在声明中用 extends 关键字继承另一个类的方法和成员。不能扩展多个类,只能继承一个基类
被继承的方法和成员可以通过用同样的名字重新声明被覆盖,除非父类定义方法时使用了 final 关键字。可以通过 parent:: 来访问被覆盖的方法或成员。

自动加载对象
定义一个 __autoload 函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
注: 在 __autoload 函数中抛出的异常不能被 catch 语句块捕获并导致致命错误。
<?php
function __autoload ($class_name
) {
require_once
$class_name . '.php'
;
}

$obj = new MyClass1
();
$obj2 = new MyClass2
();
?>
构造函数和析构函数
构造函数
PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
void __construct ( [mixed args [, ...]] )
注: 如果子类中定义了构造函数则不会暗中调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()
为了实现向后兼容性,如果 PHP 5 在类中找不到 __construct() 函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为 __construct() 的方法,但它却又不是构造函数。
析构函数
PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
void __destruct ( void )
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()
注: 析构函数在脚本关闭时调用,此时所有的头信息已经发出。
注: 试图在析构函数中抛出一个异常会导致致命错误。
<?php
class MyDestructableClass
{
function
__construct
() {
print
"In constructor\n"
;
$this-> name = "MyDestructableClass"
;
}

function
__destruct
() {
print
"Destroying " . $this ->name . "\n"
;
}
}

$obj = new MyDestructableClass
();
?>
Visibility
The visibility of a property or method can be defined by prefixing the declaration with the keywords: public, protected or private. Public declared items can be accessed everywhere. Protected limits access to inherited and parent classes (and to the class that defines the item). Private limits visibility only to the class that defines the item.

Class members must be defined with public, private, or protected.

Scope Resolution Operator (::)
The Scope Resolution Operator (also called Paamayim Nekudotayim) or in simpler terms, the double colon, is a token that allows access to static, constant, and overridden members or methods of a class.
When referencing these items from outside the class definition, use the name of the class.
class MyClass {
const
CONST_VALUE = 'A constant value'
;
}

echo MyClass:: CONST_VALUE ;
Two special keywords self and parent are used to access members or methods from inside the class definition.
class OtherClass extends MyClass
{
public static
$my_static = 'static var'
;

public static function
doubleColon
() {
echo
parent::CONST_VALUE . "\n"
;
echo
self::$my_static . "\n"
;
}
}
OtherClass::doubleColon
();



Static Keyword

Declaring class members or methods as static makes them accessible without needing an instantiation of the class. A member declared as static can not be accessed with an instantiated class object (though a static method can). Static members and methods cannot be re-defined in subclasses.

Class Constants

It is possible to define constant values on a per-class basis remaining the same and unchangeable. Constants differ from normal variables in that you don't use the $ symbol to declare or use them. Like static members, constant values cannot be accessed from an instance of the object (using $object::constant).
<?php
class
MyClass
{
const
constant = 'constant value'
;

function
showConstant
() {
echo
self::constant . "\n"
;
}
}

echo
MyClass ::constant . "\n"
;

$class = new MyClass
();
$class ->showConstant
();
// echo $class::constant; is not allowed
?>

Class Abstraction

PHP 5 introduces abstract classes and methods. It is not allowed to create an instance of a class that has been defined as abstract. Any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method's signature they cannot define the implementation.

When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or weaker) visibillity. For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public.


<?php
abstract class
AbstractClass
{
// Force Extending class to define this method
abstract protected function getValue
();
abstract protected function
prefixValue ( $prefix
);

// Common method
public function printOut
() {
print
$this->getValue () . "\n"
;
}
}

class
ConcreteClass1 extends
AbstractClass
{
protected function
getValue
() {
return
"ConcreteClass1"
;
}

public function
prefixValue( $prefix
) {
return
"{$prefix}ConcreteClass1"
;
}
}

class
ConcreteClass2 extends
AbstractClass
{
public function
getValue
() {
return
"ConcreteClass2"
;
}

public function
prefixValue ( $prefix
) {
return
"{$prefix}ConcreteClass2"
;
}
}

$class1 = new ConcreteClass1
;
$class1->printOut
();
echo
$class1-> prefixValue ('FOO_') . "\n"
;

$class2 = new ConcreteClass2
;
$class2->printOut
();
echo
$class2->prefixValue ( 'FOO_') . "\n"
;
?>

ConcreteClass1 FOO_ConcreteClass1 ConcreteClass2 FOO_ConcreteClass2
Object Interfaces

Object interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled.

借口定义同标准的类定义相同,但是不需要定义方法的实现.所有的方法定义必须是public访问级别的.

<?php
// Declare the interface 'iTemplate'
interface
iTemplate
{
public function
setVariable ($name , $var
);
public function
getHtml($template
);
}

// Implement the interface
// This will work
class Template implements
iTemplate
{
private
$vars
= array();

public function
setVariable ( $name, $var
)
{
$this->vars [ $name] = $var
;
}

public function
getHtml ($template
)
{
foreach(
$this->vars as $name => $value
) {
$template = str_replace('{' . $name . '}' , $value, $template
);
}

return
$template
;
}
}

// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements
iTemplate
{
private
$vars
= array();

public function
setVariable ( $name, $var
)
{
$this-> vars[$name ] = $var
;
}
}

?>

 instanceof 用来测定一个给定的对象是否来自指定的对象类
interface MyInterface  {
public function
Hello ( AbstractClass $obj
);
}

Overloading
Both method calls and member accesses can be overloaded via the __call, __get and __set methods. These methods will only be triggered when your object or inherited object doesn't contain the member or method you're trying to access. All overloading methods must not be defined as static.
调用方法和访问成员可以通过__call,__get和__set方法进行重载。
这些方法只有当对象或继承的对象中不包含指定的的成员或方法是才可以使用。
所有的重载方法不能定义为static.
Since PHP 5.1.0 it is also possible to overload the isset() and unset() functions via the __isset and __unset methods respectively.
void __set ( string name, mixed value )
mixed __get ( string name )
bool __isset ( string name )
void __unset ( string name )
<?php
class
Setter
{
public
$n
;
private
$x = array( "a" => 1 , "b" => 2 , "c" => 3
);

private function
__get ($nm
)
{
echo
"Getting [$nm]\n"
;

if (isset(
$this ->x[$nm
])) {
$r = $this-> x[ $nm
];
print
"Returning: $r\n"
;
return
$r
;
} else {
echo
"Nothing!\n"
;
}
}

private function
__set( $nm, $val
)
{
echo
"Setting [$nm] to $val\n"
;

if (isset(
$this->x [$nm
])) {
$this ->x[ $nm] = $val
;
echo
"OK!\n"
;
} else {
echo
"Not OK!\n"
;
}
}

private function
__isset($nm
)
{
echo
"Checking if $nm is set\n"
;

return isset(
$this->x [$nm
]);
}

private function
__unset($nm
)
{
echo
"Unsetting $nm\n"
;

unset(
$this->x [ $nm
]);
}
}

$foo = new Setter
();
$foo-> n = 1
;
$foo ->a = 100
;
$foo ->a
++;
$foo->z
++;

var_dump(isset( $foo-> a));
//true
unset($foo ->a
);
var_dump (isset($foo-> a ));
//false

// this doesn't pass through the __isset() method
// because 'n' is a public property
var_dump(isset( $foo->n
));

var_dump($foo
);
?>
Setting [a] to 100
OK!
Getting [a]
Returning: 100
Setting [a] to 101
OK!
Getting [z]
Nothing!
Setting [z] to 1
Not OK!

Checking if a is set
bool(true)
Unsetting a
Checking if a is set
bool(false)
bool(true)

object(Setter)#1 (2) {
["n"]=>
int(1)
["x:private"]=>
array(2) {
["b"]=>
int(2)
["c"]=>
int(3)
}
}
mixed __call ( string name, array arguments )

<?php
class
Caller
{
private
$x = array(1 , 2 , 3
);

public function
__call($m , $a
)
{
print
"Method $m called:\n"
;
var_dump ($a
);
return
$this->x
;
}
}

$foo = new Caller
();
$a = $foo-> test( 1, "2" , 3.4, true
);
var_dump( $a
);
?>

Method test called:
array(4) {
[0]=>
int(1)
[1]=>
string(1) "2"
[2]=>
float(3.4)
[3]=>
bool(true)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}

Object Iteration
PHP 5 provides a way for objects to be defined so it is possible to iterate through a list of items, with, for example a foreach statement. By default, all visible properties will be used for the iteration.
php5提供了迭代对象属性的方式。默认,所有的访问级别属性都可以用于迭代。
<?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:\n"
;
foreach(
$this as $key => $value
) {
print
"$key => $value\n"
;
}
}
}
$class = new MyClass
();
foreach(
$class as $key => $value
) {
print
"$key => $value\n"
;
}
echo
"\n"
;
$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
As the output shows, the foreach iterated through all visible variables that can be accessed. To take it a step further you can implement one of PHP 5's internal interface named Iterator . This allows the object to decide what and how the object will be iterated.

Object Iteration implementing Iterator
class MyIterator implements Iterator
{
private
$var
= array();

public function
__construct($array
)
{
if (
is_array ($array
)) {
$this-> var = $array
;
}
}

public function
rewind
() {
echo
"rewinding\n"
;
reset($this->var
);
}

public function
current
() {
$var = current ($this->var
);
echo
"current: $var\n"
;
return
$var
;
}

public function
key
() {
$var = key( $this->var
);
echo
"key: $var\n"
;
return
$var
;
}

public function
next
() {
$var = next($this ->var
);
echo
"next: $var\n"
;
return
$var
;
}

public function
valid
() {
$var = $this->current () !== false
;
echo
"valid: {$var}\n"
;
return
$var
;
}
}

$values = array( 1, 2,3
);
$it = new MyIterator($values
);

foreach (
$it as $a => $b
) {
print
"$a: $b\n"
;
}
output:

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:
You can also define your class so that it doesn't have to define all the Iterator functions by simply implementing the PHP 5 IteratorAggregate interface
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
;
}
}

Patterns
Patterns are ways to describe best practices and good designs. They show a flexible solution to common programming problems.
Factory
The Factory pattern allows for the instantiation of objects at runtime. It is called a Factory Pattern since it is responsible for "manufacturing" an object.
class Example
{
// The 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'
);
}
}
}

// Load a MySQL Driver
$mysql = Example::factory ('MySQL'
);

// Load a SQLite Driver
$sqlite = Example::factory( 'SQLite'
);
Singleton
The Singleton pattern applies to situations in which there needs to be a single instance of a class. The most common example of this is a database connection. Implementing this pattern allows a programmer to make this single instance easily accessible by many other objects.

<?php
class
Example
{
// Hold an instance of the class
private static $instance
;

// A private constructor; prevents direct creation of object
private function __construct
()
{
echo
'I am constructed'
;
}

// The singleton method
public static function singleton
()
{
if (!isset(
self::$instance
)) {
$c = __CLASS__
;
self::$instance = new $c
;
}

return
self :: $instance
;
}

// Example method
public function bark
()
{
echo
'Woof!'
;
}

// Prevent users to clone the instance
public function __clone
()
{
trigger_error ('Clone is not allowed.' , E_USER_ERROR
);
}

}

?>


$test = new Example ;

// This will always retrieve a single instance of the class
$test = Example ::singleton
();
$test->bark
();

// This will issue an E_USER_ERROR.
$test_clone = clone( $test
);


toomuchphp-phpman at yahoo dot com 27-Nov-2005 05:46
// Each instance of 'Customer' represents one customer!
class Customer
{

// Access a unique instance of class for a customer record
public function Unique( $CustomerID
) {
static
$instances
= array();

// a unique instance for each CustomerID
if(!isset($instances [ $CustomerID
]))
$instances [$CustomerID] = new Customer ( $CustomerID
);

return
$instances[ $CustomerID
];
}

private
$CustomerID
;

private function
__construct( $CustomerID
) {
$this ->CustomerID = $CustomerID
;
}
}

// get instance of class for customer #1
$C1 = Customer :: Unique(1
);

// get instance of class for customer #2
$C2 = Customer :: Unique(2
);

Magic Methods
The function names __construct, __destruct (see Constructors and Destructors), __call, __get, __set, __isset, __unset (see Overloading), __sleep, __wakeup, __toString, __clone and __autoload are magical in PHP classes. You cannot have functions with these names in any of your classes unless you want the magic functionality associated with them.

PHP reserves all function names starting with __ as magical. It is recommended that you do not use function names with __ in PHP unless you want some documented magic functionality.

__sleep and __wakeup
在进行序列化serialize() unserialize() 时使用__sleep停止一些需要持续化的状态(如数据库联接),反序列化时通过__wakeup重新建立__sleep的状态以恢复序列化前的环境。
__toString
允许用户控制转换到string的方式。但,只在echo()print()时会自动调用

Final Keyword
php5引入了final关键字,通过final关键字可以防止子类对以final声明的方法进行扩展。
<?php
class BaseClass
{
public function
test
() {
echo
"BaseClass::test() called\n"
;
}

final public function
moreTesting
() {
echo
"BaseClass::moreTesting() called\n"
;
}
}

class
ChildClass extends BaseClass
{
public function
moreTesting
() {
echo
"ChildClass::moreTesting() called\n"
;
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?>

Object cloning
实现可控的深层拷贝。
Creating a copy of an object with fully replicated properties is not always the wanted behavior. A good example of the need for copy constructors, is if you have an object which represents a GTK window and the object holds the resource of this GTK window, when you create a duplicate you might want to create a new window with the same properties and have the new object hold the resource of the new window. Another example is if your object holds a reference to another object which it uses and when you replicate the parent object you want to create a new instance of this other object so that the replica has its own separate copy.
An object copy is created by using the clone keyword (which calls the object's __clone() method if possible). An object's __clone() method cannot be called directly.

$copy_of_object = clone $object;
<?php
class
SubObject
{
static
$instances = 0
;
public
$instance
;

public function
__construct
() {
$this-> instance = ++self ::$instances
;
}

public function
__clone
() {
$this ->instance = ++self ::$instances
;
}
}

class
MyCloneable
{
public
$object1
;
public
$object2
;

function
__clone
()
{
// Force a copy of this->object, otherwise
// it will point to same object.
$this->object1 = clone( $this->object1
);
}
}

$obj = new MyCloneable
();

$obj ->object1 = new SubObject
();
$obj-> object2 = new SubObject
();

$obj2 = clone $obj
;


print(
"Original Object:\n"
);
print_r( $obj
);

print(
"Cloned Object:\n"
);
print_r( $obj2
);

?>

上例将输出:

Original Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)

[object2] => SubObject Object
(
[instance] => 2
)

)
Cloned Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)

[object2] => SubObject Object
(
[instance] => 2
)

)

Comparing objects

When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values, and are instances of the same class.


相同的属性和相同的值,相同类的实例


On the other hand, when using the identity operator (===), object variables are identical if and only if they refer to the same instance of the same class.


相同类的相同实例


<?php
function bool2str($bool
)
{
if (
$bool === false
) {
return
'FALSE'
;
} else {
return
'TRUE'
;
}
}

function
compareObjects(&$o1 , &$o2
)
{
echo
'o1 == o2 : ' . bool2str( $o1 == $o2 ) . "\n"
;
echo
'o1 != o2 : ' . bool2str( $o1 != $o2) . "\n"
;
echo
'o1 === o2 : ' . bool2str( $o1 === $o2) . "\n"
;
echo
'o1 !== o2 : ' . bool2str( $o1 !== $o2) . "\n"
;
}

class
Flag
{
public
$flag
;

function
Flag( $flag = true
) {
$this->flag = $flag
;
}
}

class
OtherFlag
{
public
$flag
;

function
OtherFlag( $flag = true
) {
$this-> flag = $flag
;
}
}

$o = new Flag
();
$p = new Flag
();
$q = $o
;
$r = new OtherFlag
();

echo
"Two instances of the same class\n"
;
compareObjects($o, $p
);

echo
"\nTwo references to the same instance\n"
;
compareObjects ($o, $q
);

echo
"\nInstances of two different classes\n"
;
compareObjects($o , $r
);
?>


上例将输出:

Two instances of the same class o1 == o2 : TRUE o1 != o2 : FALSE o1 === o2 : FALSE o1 !== o2 : TRUE  Two references to the same instance o1 == o2 : TRUE o1 != o2 : FALSE o1 === o2 : TRUE o1 !== o2 : FALSE  Instances of two different classes o1 == o2 : FALSE o1 != o2 : TRUE o1 === o2 : FALSE o1 !== o2 : TRUE

php5中=传递的是对象的引用;

Reflection

PHP 5 comes with a complete reflection API that adds the ability to reverse-engineer classes, interfaces, functions and methods as well as extensions. Additionally, the reflection API also offers ways of retrieving doc comments for functions, classes and methods.

The reflection API is an object-oriented extension to the Zend Engine, consisting of the following classes:


<?php
class Reflection
{ }
interface
Reflector
{ }
class
ReflectionException extends Exception
{ }
class
ReflectionFunction implements Reflector
{ }
class
ReflectionParameter implements Reflector
{ }
class
ReflectionMethod extends ReflectionFunction
{ }
class
ReflectionClass implements Reflector
{ }
class
ReflectionObject extends ReflectionClass
{ }
class
ReflectionProperty implements Reflector
{ }
class
ReflectionExtension implements Reflector
{ }
?>

例子 19-31. Basic usage of the reflection API

<?php
Reflection
::export(new ReflectionClass ('Exception'
));
?>

上例将输出:

Class [ <internal> class Exception ] {    - Constants [0] {   }    - Static properties [0] {   }    - Static methods [0] {   }    - Properties [6] {     Property [ <default> protected $message ]     Property [ <default> private $string ]     Property [ <default> protected $code ]     Property [ <default> protected $file ]     Property [ <default> protected $line ]     Property [ <default> private $trace ]   }    - Methods [9] {     Method [ <internal> final private method __clone ] {     }      Method [ <internal> <ctor> public method __construct ] {        - Parameters [2] {         Parameter #0 [ <required> $message ]         Parameter #1 [ <required> $code ]       }     }      Method [ <internal> final public method getMessage ] {     }      Method [ <internal> final public method getCode ] {     }      Method [ <internal> final public method getFile ] {     }      Method [ <internal> final public method getLine ] {     }      Method [ <internal> final public method getTrace ] {     }      Method [ <internal> final public method getTraceAsString ] {     }      Method [ <internal> public method __toString ] {     }   } }

ReflectionException extends the standard Exception and is thrown by Reflection API. No specific methods or properties are introduced。


The ReflectionFunction class lets you reverse-engineer functions.

The ReflectionParameter class retrieves information about a function's or method's parameters.


....


Type Hinting

PHP 5 introduces Type Hinting. Functions are now able to force parameters to be objects (by specifying the name of the class in the function prototype) or arrays (since PHP 5.1).

php5允许定义方法的参数类型,但只能定义是class或是array。
<?php
// An example class
class
MyClass
{
/**
* A test function
*
* First parameter must be an object of type OtherClass
*/
public function test( OtherClass $otherclass
) {
echo
$otherclass ->var
;
}


/**
* Another test function
*
* First parameter must be an array
*/
public function test_array(array $input_array
) {
print_r( $input_array
);
}
}

// Another example class
class OtherClass
{
public
$var = 'Hello World'
;
}
?>
调用指定参数类型的方法时,如果传递的参数类型不正确,将导致异常。

--
[:p] --飞扬.轻狂 [fallseir.lee]
http://fallseir.livejournal.com/
http://feed.feedsky.com/fallseir

没有评论: