河北农大软件特色班招生电话:0312-6791618 | 联系我们:0312-2019787

PHP中面向对象编程

2008-11-27 15:50 浏览次数 1
   本篇文章主要对php面向对象的部分特征进行了讲解,并通过实例程序来对php面向对象的一些特征进行了详细的阐述
 

       由于php手册从这一章节开始没有翻译,都是英文,近来自己开始学习php5中的面向对象编程,为方便学习和阅读,所以把其翻译之,发上来与大家分享,有不妥之处请大家批评指正!    
       对属性或方法的访问控制,是通过在前面添加关键字 public、protected 或 private 来实现的。由 public 所定义的类成员可以在任何地方被访问;由 protected 所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问);而由 private 定义的类成员则只能被其所在类访问。
对类成员的访问控制
类成员都必须使用关键字public、protected 或 private 进行定义
例 10.9. 声明类成员 
<?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; // // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello();// Shows Public, Protected and Priv
class MyClass2 extends MyClass    //Define MyClass2
{
      // We can redeclare the public and protected method, but not private
      protected $protected = 'Protected2';
      function printHello()
      {     
         echo $this->public;
         echo $this->protected;
         echo $this->private;
     }
}
$obj2 = new MyClass2();
echo $obj->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello();// Shows Public, Protected2, not Private
?>注意:
  在 PHP 4 中使用 var 关键字对变量进行定义的方法在 PHP 5 的面向对象语法中不再使用。为了顾及兼容性,在类中定义一个变量的话,该变量会被自动设为 public,并且产生一个 E_STRICT 警告。
对方法的访问控制
类中的方法都必须使用关键字public、protected 或 private 进行定义。如果没有设置这些关键字,则该方法会被设置成默认的 public。
例 10.10. 声明类中的方法 <?php
class MyClass     //Define MyClass
{   
      public function __construct() { }
      public function MyPublic() { }
      protected function MyProtected() { }
      private function MyPrivate() { }
      function Foo()
     {   
         $this->MyPublic();
         $this->MyProtected();
         $this->MyPrivate();
     }
}
$myclass = new MyClass;
$myclass->MyPublic(); //
$myclass->MyProtected(); //
$myclass->MyPrivate(); //
$myclass->Foo();
class MyClass2 extends MyClass      //Define MyClass2

      // This is public
     function Foo2()
     {    
         $this->MyPublic();
         $this->MyProtected();
         $this->MyPrivate();
     }
}
$myclass2 = new MyClass2;
$myclass2->MyPublic();
$myclass2->Foo2();
?>
                        第19章 类与对象(PHP5)之二:范围解析操作符(::)
        范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。把 Paamayim Nekudotayim 选作该操作符的名字似乎有些奇怪。然而,这是Zend开发小组在写Zend Engine 0.5(被用于 PHP 3 中)时所作出的决定。事实上这个词在希伯莱文就是双冒号的意思。

例 10.11. 在类的外部使用 :: 操作符
<?php
class MyClass
{   
      const CONST_VALUE = 'A constant value';
}
echo MyClass::CONST_VALUE;
?>

self和parent这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。

例 10.12. :: from inside the class definition
<?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();
?>
例 10.13. 调用父类的方法
<?php
class MyClass
{    
       protected function myFunc() {    
                echo"MyClass::myFunc()n";    
      }
}
class OtherClass extends MyClass

     // Override parent's definition
     public function myFunc()
     {   
         // But still call the parent function
         parent::myFunc();
         echo "OtherClass::myFunc()n";
     }
}
$class = new OtherClass();
$class->myFunc();
?> 
                        第19章 类与对象(PHP5)之三:静态关键字(Static Keyword)
        声明静态的类的成员和方法,使它不需要一个类的实例.一个static成员的声明不能通过一个类对象的实例来访问(尽管一个静态方法可以)。
静态声明必须在可见性声明之后。为了兼容PHP 4,如果没有可见性被声明,那么成员和方法将被当作是已经声明为public。
由于静态方法可以调用非对象实例,伪变量$this不可以在声明为静态的方法中使用。
事实上static方法调用形式在编译时被确定。当使用必须要声明的类名时,方法是完全标识和无继承规则的应用。当使用必须要声明的类名时,这种方法就被完全确认,而且没有使用继承的规则。
如果self已经被声明,那么self就被当前所属的类所解释。也不适用与继承规则。静态属性不能通过箭头操作符->.访问非静态方法,这将产生一个E_STRICT 级的警告。
例子 19-13. 静态成员的例子
<?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
// $foo::my_static is not possible
print Bar::$my_static."n";
$bar = new Bar();
print $bar->fooStatic()."n";
?>

例子 19-14.静态方法实例(Static method example) <?php
class Foo
{    
      public static function aStaticMethod() {      }
}
Foo::aStaticMethod();

                        第19章 类与对象(PHP5)之四:类常量(Class Constants) 
       可以在每个基类中定义常量使它保持不变。在你不使用$符号去声明或使用它时,常量不同于普通变量。就象静态成员,常量值不能通过对象的实例来访问(而应使用$object::constant). 常量值必须是一个常量表达式,而不是一个变量,一个类的成员,一个数学表达式或函数调用的结果。
例子 19-15. 定义并使用一个常量
<?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
?> 

                    第19章 类与对象(PHP5)之五:抽象类(Class Abstraction)
        PHP 5中引入了抽象类和抽象方法。不允许创建一个已经定义为abstract的类的一个实例。任何至少包含一个抽象方法的类也必须是抽象的。被定义为抽象的方法仅仅是声明方法的一个信号,并不能定义它们的实现。
当从一个抽象类继承时,在父类中所有抽象方法的标记的声明必须通过子类定义;另外,这些方法必须用定义相同的访问属性。例如,如果方法被定义为protected类型,执行函数必须定义为protected或public.
例子 19-16. 抽象类例子
<?php
abstract class AbstractClass
{   
     // Force Extending class to define this method
     abstract protected function getValue();
     abstract protected function prefixValue($prefix);
     public function printOut()   // Common method
     {   
         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旧代码拥有非用户自定义的命名为abstract的类或函数将要运行如果没有被修改。

                         第19章 类与对象(PHP5)之六:对象接口(Object Interfaces)
         对象接口允许你创建一个指定类的方法的执行代码,而不必说明这些方法是如何被操作(处理)的。
接口被用来定义接口关键字的使用,同样作为一个标准类,但没有任何方法有它们内容的定义。
在接口中所有的方法必须声明为public,这是接口的特性。
implements (执行,实现)
为了实现一个接口,使用了implements操作。在接口中所有的方法必须在一个类的内部实现;疏忽这些将导致一个致命错误。如果渴望通过使用一个逗号分开每个接口,类可以实现多个接口。
例子 19-17. 接口实例

<?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
//methos and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{  
      private $vars = array();
      public function setVariable($name,$var){  
                          $this->vars[$name] = $var;  
     }
}
?>

                       第19章 类与对象(PHP5)之七:重载(Overloading)
       方法调用和成员访问都能通过__call,__get和__set方法被加载。这些方法将只有当你试图访问不包括成员或方法的对象或继承对象时触发。不是所有的重载方法都必须被定义为static.
从PHP 5.1.0开始也可以通过__isset()和__unset()方法逐个重载isset()和unset()函数。
成员函数重载(Member overloading)
void __set ( string name, mixed value )
mixed __get ( string name )
bool __isset ( string name )
void __unset ( string name )
类成员可以通过定义这些指定的特定方法加载类中的自定义代码。$name参数被用来命名变量,这些变量必须是被设置的或返回的。__set()方法的$value参数指定设置$name的对象的值。
例子 19-18.使用__get,__set,__isset和__unset重载的例子
<?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: $rn";
             return $r;
         } else {  
            echo "Nothing!n";    
        }
     }
     private function __set($nm, $val)
     {  
        echo "Setting [$nm] to $valn";
         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 setn";
          return isset($this->x[$nm]);
     }
     private function __unset($nm)
     { 
        echo "Unsetting $nmn";
         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)
   }
}
方法重载(Method overloading)
mixed __call ( string name, array arguments )
类方法可以通过定义这些指定的特定方法加载类中的自定义代码。$name参数被用来命名那些被请求的函数名。Arguments在定义为array的函数的$arguments参数中将被传递。从__call()方法返回的值将被返回方法的访问者。
例子 19-19.使用__call重载的实例

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

                      第19章 类与对象(PHP5)之八:对象迭代(Object Iteration)
       PHP5提供一个为对象定义通过一连串的消息被重述的途径成为可能,例如使用一个foreach语句。默认地,所有可见的属性将用来迭代(反复)。
例子 19-20. 简单的对象迭代(Simple Object Iteration) <?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 => $valuen";   }
     }
}
$class = new MyClass();
foreach($class as $key => $value){    print "$key => $valuen";   }
echo "n";
$class->iterateVisible();
?>

如输出显示,foreach重述能通过全部可见变量被访问。更进一步,你可以实现一个PHP5的指定的内在接口迭代器(Iterator)。允许对象描述什么是对象重述和对象如何被重述的。

                       第19章 类与对象(PHP5)之九:模式(Patterns)
   模式是最好的实践和设计的描述方法。它给普通的编程问题展示一个可变的解决方案。
  工厂模式(Factory)
  工厂模式允许在运行的时间实例化一个对象。自从工厂模式命名以来,制造一个对象是可能的。
例子 19-23.工厂方法 (Factory Method)
<?php
class Example
{   
  public static function factory($type)//The factory method
     {  
      if (include_once 'Drivers/'.$type.'.php')
          {    
            $classname = 'Driver_' . $type;
             return new $classname;
         }else{   
              throw new Exception ('Driver not found');   
        }
     }
}
?>

在类中允许定义一个驱动器在不工作时被加载的方法。如果类例子是一个数据库抽象类,可以象如下这样加载一个MySQL和SQLite驱动
<?php
   $mysql = Example::factory('MySQL'); // Load a MySQL Driver
   $sqlite = Example::factory('SQLite'); // Load a SQLite Driver
?> 单独模式(Singleton)
单模式适用于需要一个类的单独接口的情况。最普通的例子是数据库连接。这个模式的实现
允许程序员构造一个通过许多其他对象轻松地访问的单独接口。
例子 19-24.单模式函数(Singleton Function)

<?php
class Example
{   
     // Hold an instance of the class
     private static $instance;
     private function __construct()//A private constructor;prevents direct creation of object
     {   
         echo 'I am constructed';      
     }
      public static function singleton()// The singleton method
     {   
       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);   }
}
?>
允许类实例的一个单独接口被重新获得。
<?php
$test = new Example; // This would fail because the constructor is private
$test = Example::singleton();// This will always retrieve a single instance of the class
$test->bark();
$test_clone = clone($test); // This will issue an E_USER_ERROR.
?>

<?php
class MyIterator implements Iterator
{    private $var = array();
     public function __construct($array)
     {    
          if (is_array($array)){   $this->var = $array; }
     }
     public function rewind()
     {     
         echo "rewindingn";
         reset($this->var);
}
     public function current()
     { 
        $var = current($this->var);
         echo "current: $varn";
         return $var;
     }
     public function key()
     { 
        $var = key($this->var);
         echo "key: $varn";
         return $var;
     }
     public function next()
     {   
         $var = next($this->var);
         echo "next: $varn";
         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: $bn";   }
?>
上例将输出:
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: 在定义类时你也可以不必通过简单实现PHP5的IteratorAggregate接口定义所有的迭代器函数。
例19-22.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]nn";   }
?>
上例将输出: 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:

                  第19章 类与对象(PHP5) 之十:魔法方法(Magic Methods)
函数名__construct, __destruct (注意构造函数和析构函数), __call, __get, __set, __isset, __unset (注意重载), __sleep, __wakeup, __toString, __set_state, __clone and __autoload是PHP类里边的魔法函数.
函数名 __construct, __destruct(注意构造函数和析构函数), __call, __get, __set, __isset, __unset (see 注意重载), __sleep, __wakeup, __toString, __set_state, __clone and __autoload在PHP类里是魔术的.在任何类里你不能用这些名字给函数命名除非你想与它们的魔术功能性相关联。
     注意: PHP储量将所有用__开始的函数名作为魔术函数。推荐地,在PHP里不能用__做函数名除非你想用文件证明是魔术函数。
__sleep()和__wakeup()
serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。
使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。
相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。
使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
例子 19-25. Sleep and wakeup

<?php
class Connection
{  
     protected $link;
     private $server, $username, $password, $db;
     public function __construct($server, $username, $password, $db)
     {    
         $this->server = $server;
         $this->username = $username;
         $this->password = $password;
         $this->db = $db;
         $this->connect();
     }
     private function connect()
     {   
        $this->link = mysql_connect($this->server, $this->username, $this->password);
         mysql_select_db($this->db, $this->link);
     }
     public function __sleep() {    mysql_close($this->link);    }
     public function __wakeup() {    $this->connect();    }
}
?>
__toString
__toString方法允许一个类决定当它被修改为string类型时是如何起作用的。
例子 19-26.Simple example
<?php
class TestClass// Declare a simple class
{
     public $foo;
     public function __construct($foo){   $this->foo = $foo;   }
     public function __toString()      {   return $this->foo;    }
}
$class = new TestClass('Hello');
echo $class;
?>
上例将输出:Hello
__toString方法将只在使用echo()和print()直接地组合时被调用是一个有效的注释方法。
例子 19-27. Cases where __toString is called
<?php
echo $class; //__toString called
echo 'text',$class; //__toString called (still a normal parameter for echo)
echo 'text'.$class; // __toString not called (concatenation operator used first)
echo (string)$class; //__toString not called (cast to string first)
echo "text $class";//__toString not called (cast to string first)
?>

__set_state
从PHP 5.1.0开始static方法是通过var_export()函数来访问类接口的。这个方法的唯一参数是一个包含属性出口的以为array(‘property’=value,…)形式的数组

                       第19章:类与对象(PHP5)之十一:最终关键字(Final Keyword)
        PHP5引入了最终关键字,防止子类使用final从一个重要的方法做定义的前缀。如果类本身已经被定义为final,类将不能被扩展。
例子 19-28.Final方法实例

<?php
class BaseClass
{    
    public function test()
     {   
         echo "BaseClass::test() calledn";  
     }
     final public function moreTesting()
     {
         echo"BaseClass::moreTesting() calledn";
     }
}
class ChildClass extends BaseClass
{
    public function moreTesting()
    {
        echo "ChildClass::moreTesting() calledn";
    }
}
//Results in Fatal error:Cannot override final method BaseClass::moreTesting()
?>
例子 19-29. Final 类实例
<?php
final class BaseClass
{    
     public function test()
      {  
          echo "BaseClass::test() calledn";  
      }
    //Here it doesn't matter if you specify the function as final or not
    final public function moreTesting()
    {
        echo"BaseClass::moreTesting() calledn";
    }
}
class ChildClass extends BaseClass {   }
//Results in Fatal error:Class ChildClass may not inherit from final class (BaseClass)
?> 
                       19章 类与对象(PHP5)之十二:对象克隆(Object cloning)
        通过完全地复制属性创建一个对象的拷贝不是通常想要的行为。需求的一个好的实例适合于拷贝构造函数,
如果有一个对象描述一个GTK窗口和对象保存这个GTK窗口的资源,当你创建一个副本,你或许想创建一个相同的属性新窗口使用和保存新对象资源的新窗口。另一个例子是当你复制父对象时如果保存一个引用给另一个对象,你想创建其他类的一个新实例来分开拷贝所属的复制品。一个对象的拷贝是使用clone关键字来创建的(如果可能的话可以调用对象的__clone()方法),一个对象的__clone()方法不能被直接声明。
$copy_of_object = clone $object;

当一个对象被克隆时,PHP5将执行一个所有对象的属性的浅拷贝。任何对其它变量引用的属性将只保留引用。如果一个__clone()方法被定义,然后重新创建一个对象的克隆方法来允许任何必需的属性当它需要被改变时调用。
例子 19-30. 克隆一个对象

<?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()
     {
        $this->object1=clone($this->object1);//Force a copy of this->object,otherwise it will point to same object.
     }
}
$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
         )
)

 1  2 [下一页]
上一篇: 下一篇:

相关主题:php,php面向对象,php总结