日新论坛's Archiver

wl1011 发表于 2008-4-19 09:32

PHP - 第六课 类与对象(PHP 5)

[b][size=4]一、基本概念
[/size]  class[/b]

       每个类的定义都以关键字 class 开头,后面跟着类名,可以是任何非 PHP [color=#0000ff]保留字[/color]的名字。后面跟着一对花括号,里面包含有类成员和方法的定义。伪变量 $this 可以在当一个方法在对象内部调用时使用。$this 是一个到调用对象(通常是方法所属于的对象,但也可以是另一个对象,如果该方法是从第二个对象内[color=#0000ff]静态[/color]调用的话)的引用。看下面例子:

[b]Example#1 面向对象语言中的 $this 变量:[/b] 复制内容到剪贴板 代码:[font=NSimsun]<?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();
?> [/font]
上例将输出: 复制内容到剪贴板 代码:[font=NSimsun]$this is defined (a)
$this is not defined.
$this is defined (b)
$this is not defined.[/font]
[b]Example#2 简单的类定义:[/b] 复制内容到剪贴板 代码:[font=NSimsun]<?php
class SimpleClass
{
    // 成员声明
    public $var = 'a default value';

    // 方法声明
    public function displayVar() {
        echo $this->var;
    }
}
?> [/font]
[b]Example#3 类成员的默认值:[/b] 复制内容到剪贴板 代码:[font=NSimsun]<?php
class SimpleClass
{
    // 无效的类成员定义:
    public $var1 = 'hello '.'world';
    public $var2 = <<<EOD
hello world
EOD;
    public $var3 = 1+2;
    public $var4 = self::myStaticMethod();
    public $var5 = $myVar;

    // 正确的类成员定义:
    public $var6 = myConstant;
    public $var7 = self::classConstant;
    public $var8 = array(true, false);


}
?> [/font]
引用:[indent]Note: 除此之外还有不少用于处理类与对象的函数,详情参见 [url=http://www.php.net/manual/zh/ref.classobj.php][color=#0000ff]类 / 对象函数[/color][/url] [/indent]
[b]new[/b]
要创建一个对象的实例,必须创建一个新对象并将其赋给一个变量。当创建新对象时该对象总是被赋值,除非该对象定义了[color=#0000ff]构造函数[/color]并且在出错时抛出了一个[color=#0000ff]异常[/color]。

[b]Example#4 创建一个实例e:[/b] 复制内容到剪贴板 代码:
[font=NSimsun]<?php
$instance = new SimpleClass();
?> [/font]
当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用克隆给一个已创建的对象建立一个新实例。

[b]Example#5 对象赋值:[/b] 复制内容到剪贴板 代码:
[font=NSimsun]<?php
$assigned   =  $instance;
$reference  =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?> [/font]
上例将输出: 复制内容到剪贴板 代码:
[font=NSimsun]NULL
NULL
object(SimpleClass)#1 (1) {
   ["var"]=>
     string(30) "$assigned will have this value"
}[/font]
extends一个类可以在声明中用 extends 关键字继承另一个类的方法和成员。不能扩展多个类,只能继承一个基类。
被继承的方法和成员可以通过用同样的名字重新声明被覆盖,除非父类定义方法时使用了 [color=#0000ff]final[/color] 关键字。可以通过 [color=#0000ff]parent::[/color] 来访问被覆盖的方法或成员。

[b]Example#6 简单的类继承:[/b] 复制内容到剪贴板 代码:
[font=NSimsun]<?php
class ExtendClass extends SimpleClass
{
    // Redefine the parent method
    function displayVar()
    {
        echo "Extending class\n";
        parent::displayVar();
    }
}

$extended = new ExtendClass();
$extended->displayVar();
?> [/font]
上例将输出: 复制内容到剪贴板 代码:
[font=NSimsun]Extending class
a default value[/font]
[b]自动加载对象:[/b]

     很多开发者写面向对象的应用程序时对每个类的定义建立一个 PHP 源文件。一个很大的烦恼是不得不在每个脚本(每个类一个文件)开头写一个长长的包含文件列表。
在 PHP 5 中,不再需要这样了。可以定义一个 __autoload 函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。 引用:[indent]
[b]Note[/b]: 在 __autoload 函数中抛出的异常不能被 [url=http://www.php.net/manual/zh/language.exceptions.php][color=#0000ff]catch[/color][/url] 语句块捕获并导致致命错误。 [/indent]
[b]Example#1 Autoload 例子:[/b]
本例尝试分别从 MyClass1.php 和 MyClass2.php 文件中加载 [i]MyClass1[/i] 和 [i]MyClass2[/i] 类。 复制内容到剪贴板 代码:
[font=NSimsun]<?php
function __autoload($class_name) {
    require_once $class_name . '.php';
}

$obj  = new MyClass1();
$obj2 = new MyClass2();
?> [/font]

[[i] 本帖最后由 wl1011 于 2008-4-19 09:35 编辑 [/i]]

wl1011 发表于 2008-4-19 09:33

构造函数和析构函数[size=4][b]二、构造函数[/b][/size]
void __construct ([ mixed $args [, $... ]] )

PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。 引用:[indent]
[b]Note[/b]: 如果子类中定义了构造函数则不会暗中调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 [b]parent::__construct()[/b]。 [/indent]
[b]Example#1 使用新标准的构造函数[/b] 复制内容到剪贴板 代码:<?php
class BaseClass {
   function __construct() {
       print "In BaseClass constructor\n";
   }
}

class SubClass extends BaseClass {
   function __construct() {
       parent::__construct();
       print "In SubClass constructor\n";
   }
}

$obj = new BaseClass();
$obj = new SubClass();
?>
为了实现向后兼容性,如果 PHP 5 在类中找不到 [b]__construct()[/b] 函数,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为 [b]__construct()[/b] 的方法,但它却又不是构造函数。


析构函数void [b][b]__destruct[/b][/b] ( void )
PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。


[b]Example#2 析构函数示例:[/b] 复制内容到剪贴板 代码:<?php
class MyDestructableClass {
   function __construct() {
       print "In constructor\n";
       $this->name = "MyDestructableClass";
   }

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

$obj = new MyDestructableClass();
?>
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 [b]parent::__destruct()[/b]。 引用:[indent]Note: 析构函数在脚本关闭时调用,此时所有的头信息已经发出。 [/indent]
引用:[indent]
[b]Note[/b]: 试图在析构函数中抛出一个异常会导致致命错误。 [/indent]

wl1011 发表于 2008-4-19 09:33

访问控制[b][size=4]三、访问控制[/size][/b]

       对属性或方法的访问控制,是通过在前面添加关键字 public、protected 或 private 来实现的。由 public 所定义的类成员可以在任何地方被访问;由 protected 所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问);而由 private 定义的类成员则只能被其所在类访问。

[b]对类成员的访问控制[/b]

类成员都必须使用关键字public、protected 或 private 进行定义
[b]Example#1 声明类成员:[/b] 复制内容到剪贴板 代码:
<?php
/**
* Define MyClass
*/
class MyClass
{
    public $public = 'Public';
    protected $protected = 'Protected';
    private $private = 'Private';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj = new MyClass();
echo $obj->public; // 这行能被正常执行
echo $obj->protected; // 这行会产生一个致命错误
echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private


/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
    // 可以对 public 和 protected 进行重定义,但 private 而不能
    protected $protected = 'Protected2';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj2 = new MyClass2();
echo $obj->public; // 这行能被正常执行
echo $obj2->private; // 未定义 private
echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2,但不会输出 Private

class Bar
{
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }

    public function testPublic() {
        echo "Bar::testPublic\n";
    }
   
    private function testPrivate() {
        echo "Bar::testPrivate\n";
    }
}

class Foo extends Bar
{
    public function testPublic() {
        echo "Foo::testPublic\n";
    }
   
    private function testPrivate() {
        echo "Foo::testPrivate\n";
    }
}

$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate
                // Foo::testPublic
?>
引用:[indent]
[b]Note[/b]: 为了兼容性考虑,在 PHP 4 中使用 [i]var[/i] 关键字对变量进行定义的方法在 PHP 5 中仍然有效(只是作为 public 关键字的一个别名)。在 PHP 5.1.3 之前的版本,该语法会产生一个 [b]E_STRICT[/b] 警告。 [/indent]
[b]对方法的访问控制:[/b]


类中的方法都必须使用关键字public、protected 或 private 进行定义。如果没有设置这些关键字,则该方法会被设置成默认的 public。


[b]Example#2 声明类中的方法:[/b] 复制内容到剪贴板 代码:
<?php
/**
* Define MyClass
*/
class MyClass
{
    // 构造函数必须是 public
    public function __construct() { }

    // 声明一个 public 的方法
    public function MyPublic() { }

    // 声明一个 protected 的方法
    protected function MyProtected() { }

    // 声明一个 private 的方法
    private function MyPrivate() { }

    // 这个方法也是 public 的
    function Foo()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}

$myclass = new MyClass;
$myclass->MyPublic(); // 这行能被正常执行
$myclass->MyProtected(); // 这行会产生一个致命错误
$myclass->MyPrivate(); // 这行会产生一个致命错误
$myclass->Foo(); // Public、Protected 和 Private 都被调用了


/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
    // This is public
    function Foo2()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate(); // 这行会产生一个致命错误
    }
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 这行能被正常执行
$myclass2->Foo2(); // Public 和 Protected 都被调用了,但 Private 不会被调用
?>

wl1011 发表于 2008-4-19 09:34

范围解析操作符(::)[b][size=4]四、范围解析操作符(::)[/size][/b]
[b][size=4][/size][/b]
       范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问[color=#0000ff]静态[/color]成员、方法和[color=#0000ff]常量[/color],还可以用于覆盖类中的成员和方法。

       当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。

       把 Paamayim Nekudotayim 选作该操作符的名字似乎有些奇怪。然而,这是 Zend 开发小组在写 Zend Engine 0.5 (被用于 PHP 3 中)时所作出的决定。事实上这个词在希伯莱文就是双冒号的意思。

[b]Example#1 在类的外部使用 :: 操作符[/b] 复制内容到剪贴板 代码:
<?php
class MyClass {
    const CONST_VALUE = 'A constant value';
}

echo MyClass::CONST_VALUE;
?>
[i]self[/i] 和 parent 这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。

[b]Example#2 :: from inside the class definition
[/b]复制内容到剪贴板 代码:<?php

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();
?>
当一个子类覆盖其父类中的方法时,PHP 不会再执行父类中已被覆盖的方法,直到子类中调用这些方法为止。这种机制也作用于 [color=#800080]构造函数和析构函数[/color]、[color=#800080]重载[/color] 及 [color=#0000ff]魔术[/color] 函数。

[b]Example#3 调用父类的方法[/b] 复制内容到剪贴板 代码:
<?php
class MyClass
{
    protected function myFunc() {
        echo "MyClass::myFunc()\n";
    }
}

class OtherClass extends MyClass
{
    // 覆盖父类中的方法
    public function myFunc()
    {
        // 但仍然可以调用已被覆盖的方法
        parent::myFunc();
        echo "OtherClass::myFunc()\n";
    }
}

$class = new OtherClass();
$class->myFunc();
?>
static 关键字[b][size=4]五、Static 关键字[/size][/b]

     把类的成员属性或成员函数声明为static属性,这样不需要实例化类就可以访问它们了。如果一个成员被声明为static,那对象就无法访问它(除了static的成员函数)。

     为了兼容php4,如果没有显式地声明成员的属性(public, protected, private),那么它就为被默认声明为public。

     由于static成员无需类实例化成对象就可以被访问,伪变量$this不能在声明为static的成员函数内使用。

     static属性不能使用对象的操作符->进行访问。

     调用一个非static的方法会产生一个E_STRICT级别的警告。

     从php5.3.0以后,可以使用变量引用一个类。关键字如[i]self[/i], [i]parent[/i] or [i]static[/i] 不能在动态类引用中使用。

[b]Example#1 Static member example:[/b] 复制内容到剪贴板 代码:
<?php
class Foo
{
    public static $my_static = 'foo';

    public function staticValue() {
        return self::$my_static;
    }
}

class Bar extends Foo
{
    public function fooStatic() {
        return parent::$my_static;
    }
}


print Foo::$my_static . "\n";

$foo = new Foo();
print $foo->staticValue() . "\n";
print $foo->my_static . "\n";      // Undefined "Property" my_static

print $foo::$my_static . "\n";
$classname = 'Foo';
print $classname::$my_static . "\n";

print Bar::$my_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>

[color=#000000][b]Example#2 Static method example:[/b][/color]


[color=#000000]复制内容到剪贴板 代码:
<?php
class Foo {
    public static function aStaticMethod() {
        // ...
    }
}

Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod();
?>
[/color]

wl1011 发表于 2008-4-19 09:35

Class Constants[b][size=4]Class Constants[/size][/b]
   
     您可以在每一个类定义一个不变的常量值,且无法修改。常量跟普通变量的不同在于,常量不能使用$符号来声明和使用他们。常量的值必须是一个常量表达式,例如,不是一个变量,类的成员属性、方法,函数,带有任何算术符号的结果。

[b]Example#1 Defining and using a constant[/b] 复制内容到剪贴板 代码:
<?php
class MyClass
{
    const constant = 'constant value';

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

echo MyClass::constant . "\n";

$classname = "MyClass";
echo $classname::constant . "\n";

$class = new MyClass();
$class->showConstant();

echo $class::constant."\n";
?>
Class Abstraction[b]Class Abstraction(抽象类)[/b]

php5引入了抽象类以及方法,抽象类是不允许被实例化为对象的。任何含有一个抽象的方法的类就被定义为抽象类。抽象方法仅仅是声明它的签名,但不定义方法。

从一个抽象类继承之后,所有在基类被标记为抽象的方法都必须在子类中定义,而且,这些方法都必须定位为相同的访问控制(至少是一个更严格的类型)(public, protected, private)。例如,假设一个抽象的方法被定义为protected,那么此方法的实现也必须是protected,或public,但不能是private.

[b]Example#1 Abstract class example:[/b] 复制内容到剪贴板 代码:
<?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";
?>
上例将输出: 引用:[indent]
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2[/indent]
Object Interfaces[b][size=4]Object Interfaces(接口)[/size][/b]

接口就是声明一些方法,使用接口的类必须定义这些方法。接口本身只是声明方法,但是不定义这些方法。

接口的定义是使用[b]interface[/b]关键字,其他定义同类,唯一不同的是不要定义接口的任何方法。

接口中的方法全部的修饰符都必须是public。

[i][b]implements[/b][/i]

要使用接口,就用[i]implements[/i] 操作符。所有在接口中声明的方法必须在类中定义,否则会导致一个致命的错误。一个类可以使用多个接口,接口之间用逗号隔开。 引用:[indent]
注意:类不能使用具有相同名字的方法的2个接口,因为他们会产生分歧。[/indent]
[b]Example#1 Interface example[/b] 复制内容到剪贴板 代码:


<?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;
    }
}

?>

wl1011 发表于 2008-4-19 09:37

Overloading[b][size=4]Overloading(重载)[/size][/b]

      通过 __call, __get and __set这些特殊的方法, 成员方法的调用以及成员属性的访问都可以被重载。只有当你试图去访问一些对象里头不存在的方法或属性时,这些特殊的方法才会被触发。所有重载的方法都不能被定义为static,且这些方法必须是public。

      从PHP 5.1.0 起,[color=#0000ff]isset()[/color] and [color=#0000ff]unset()[/color]同样可以被重载,只要你分别使用__isset and __unset 方法即可。方法__isset的调用同empty()。

      成员属性重载:

      void [b][b]__set[/b][/b] ( string $name , mixed $value )
      mixed [b][b]__get[/b][/b] ( string $name )
      bool [b][color=#0000ff]__isset[/color][/b] ( string $name )
      void [b][color=#0000ff]__unset[/color][/b] ( string $name )

      你可以在你的类里,用这些特殊的方法来定义重载的成员属性。$name是类的成员属性,他是一个变量,你可以在__set() 方法里设置成员属性以及他的值。

      注意:__set()不接受引用参数。

[b]Example#1 overloading with __get, __set, __isset and __unset example:[/b] 复制内容到剪贴板 代码:
<?php
class Setter
{
    public $n;
    private $x = array("a" => 1, "b" => 2, "c" => 3);

    public 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";
        }
    }

    public 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";
        }
    }

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

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

    public 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":"Setter":private]=>
  array(2) {
    ["b"]=>
    int(2)
    ["c"]=>
    int(3)
  }
}
[b]成员方法重载:[/b]
mixed [b][b]__call[/b][/b] ( string $name , array $arguments )
魔术方法 __call() 允许你调用一个不存在的方法。$name 是调用的方法名,$arguments 是参数数组。

[b]Example#2 overloading with __call example:[/b] 复制内容到剪贴板 代码:
<?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[b][size=4]Object Iteration(对象枚举)[/size][/b]
    php5提供了一种可以枚举对象的成员属性和成员方法的途径,可以使用foreach语句来遍历他们。缺省情况下,所有可见的成员才可以被用来枚举。

    [b]Example#1 Simple Object Iteration[/b] 复制内容到剪贴板 代码:
<?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



通过上例的输出可以看出,foreach可以访问所有可见的成员。为了更深入理解这个机制,你可以实现php5的内部接口,[i]Iterator。[/i]这样对象就可以决定此对象如何进行枚举以及可以枚举什么。

[b]Example#2 Object Iteration implementing Iterator[/b] 复制内容到剪贴板 代码:
<?php
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";
}
?>
上例将输出: 复制内容到剪贴板 代码:
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:



当然你也可以自己定义一个类,必须实现所有[i]Iterator[/i] 接口的方法,而只需简单地实现php5 的 [i]IteratorAggregate[/i]  接口。

[b]Example#3 Object Iteration implementing IteratorAggregate[/b] 复制内容到剪贴板 代码:
<?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]\n\n";
}
?>
上例将输出: 复制内容到剪贴板 代码:
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:

081003 发表于 2008-10-3 13:48

新加的空白文章2

*** 作者被禁止或删除 内容自动屏蔽 ***

abcd960 发表于 2008-12-29 16:37

这么好的贴子为什么没人顶呢?支持一个!

[size=6]这么好的贴子为什么没人顶呢?支持一个!
[/size]
[url=http://www.qzxseo.org]重庆seo[/url]

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.