文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>php5的面向对象学习笔记(一)

php5的面向对象学习笔记(一)

时间:2006-07-27  来源:jingzhi

一直没有系统的学习php5关于面向对象的新特性,因为他没有java那么严格。后来发现用java的语法写php在5里面运行的很好。于是今天翻翻手册,写点儿笔记。
因为有学习过面向对象的编程。也看过 java programming ,所以觉得一些东西只是更
OO了。写的比较简单,如果不懂建议先学学oo的编程基础。对抽象类、接口、重载、模式、对象克龙有比较多的介绍。

PHP 5 引入了新的对象模型(Object Model)。完全重写了 PHP 处理对象的方式,允许更佳性能和更多特性。

一、首先是定义:
每个类的定义都以关键字 class 开头,后面跟着类名,可以是任何非 PHP
保留字
的名字。后面跟着一对花括号,里面包含有类成员和方法的定义。伪变量 $this 可以在当一个方法在对象内部调用时使用。$this 是一个到调用对象(通常是方法所属于的对象,但也可以是另一个对象,如果该方法是从第二个对象内
静态
调用的话)的引用。看下面例子:
例子 19-1. 简单的类定义
class SimpleClass
{
   // 成员声明
   public $var = 'a default value';
   // 方法声明
   public function displayVar() {
       echo $this->var;
   }
}
?>
new
要创建一个对象的实例,必须创建一个新对象并将其赋给一个变量。当创建新对象时该对象总是被赋值,除非该对象定义了
构造函数
并且在出错时抛出了一个
异常

extends
一个类可以在声明中用 extends 关键字继承另一个类的方法和成员。不能扩展多个类,只能继承一个基类。
被继承的方法和成员可以通过用同样的名字重新声明被覆盖,除非父类定义方法时使用了
final
关键字。可以通过
parent::
来访问被覆盖的方法或成员。
例子 19-4. 简单的类继承
class ExtendClass extends SimpleClass
{
   // Redefine the parent method
   function displayVar()
   {
       echo "Extending class\n";
       parent::displayVar();
   }
}
$extended = new ExtendClass();
$extended->displayVar();
?>
上例将输出:
Extending class
a default value

二、接下来就是自动加载
自动加载对象
很多开发者写面向对象的应用程序时对每个类的定义建立一个 PHP 源文件。一个很大的烦恼是不得不在每个脚本(每个类一个文件)开头写一个常常的包含文件列表。
在 PHP 5 中,不再需要这样了。可以定义一个 __autoload 函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
注: 在 __autoload 函数中抛出的异常不能被
catch
语句块捕获并导致致命错误。
我对这部分没理解清楚,我的感觉是,他是说在调用__autoload函数之前,必须已经声明了要引用文件的名字。
三、再就是构造函数和析构函数
void __construct ( [mixed args [, ...]] )
PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
注: 如果子类中定义了构造函数则不会暗中调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。
另外php5为兼容以前的版本,当没有__construct()时,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。当然如果这时你声明了一个__construct()而什么都不做,那我也没办法了。
void __destruct ( void )
PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
接下来是可见性:visibility
成员和方法的可见性可以在定义时冠以关键字:public, protected or private来声明。这点和java/c++已经很相像,不再赘述。
在php5中,类成员应该指定public, protected,private中的一种可见性。这样使脚本更OO
四、再然后是::操作符。
使用::操作符,你可以访问
static
,
constant
成员,并能访问重载类的成员或方法。
在类外部,可以classname::mumber/method的方式访问类的成员/方法。
而在类的内部,可以使用self 和 parent 这两个关键字来访问类的成员/方法。
此外在子类中要访问父类的成员/方法也要用::
五、再接下来是static 关键字
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.
以static关键字声明类的成员/方法使他们可以无须实例即可访问。一个成员声明为static,那么他是不可以被这个类的实例来访问的(虽然静态方法可以)。静态成员和方法不能在子类中被重定义(重载),当然final关键字也有此功能。
The static declaration must be after the visibility declaration. For compatibility with PHP 4, if no
visibility
declaration is used, then the member or method will be treated as if it was declared as public.
这里要注意的是,static关键字的声明必须在可见性声明之后,为兼容php4,如果没有声明可见性,那么成员或方法将被以public对待。
Because static methods are callable without an instance of the object created, the pseudo variable $this is not available inside the method declared as static.
因为静态(static)方法不需要创建实例即可调用,因此伪$this变量,不能出现在静态(static)方法的定义中。这也是要注意的。
In fact static method calls are resolved at compile time. When using an explicit class name the method is already identified completely and no inheritance rules apply. If the call is done by self then self is translated to the current class, that is the class the code belongs to. Here also no inheritance rules apply.
事实上静态方法在便宜时即被调用,当直接以类名调用该方法前,他已经确定存在并不需实例化。如果调用是在类内部(self)那么self被转移到当前类。也是没有应用实例。(这段翻译不好,总之,静态方法是在编译时期就已经定义好的了,而不是在使用时才动态分配空间和设置参数。)
Static properties cannot be accessed through the object using the arrow operator ->.
静态属性不能通过对象用->访问。
Calling non-static methods statically generates an E_STRICT level warning.
静态的调用非静态方法会产生一个代码级警告。
例子 19-13. Static member example
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
class Foo {
   public static function aStaticMethod() {
       // ...
   }
}
Foo::aStaticMethod();
?>
六、类常量
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).
定义不变值的类常量来承载不变的信息是可行的。因为像static成员一样,constant常量是不可以被类的实例(对象)用$object::constant的方式访问的。
例子 19-15. Defining and using a constant
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
?>
七、类的抽象
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.
在php5中引入了抽象类和抽象方法的概念。(如同java/c++中那样)他不允许创建抽象类的实例,至少含有一个抽象方法。抽象方法只定义方法名称(签名)而不定义具体实现,等等。
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.
当抽象类被继承时,父类中所有的抽象方法必须在子类中定义。此外,这些方法的可见性定义必须与父类相同或比父类弱。
例子 19-16. Abstract class example
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 allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled.
对象接口允许你在没有定义类的特定方法怎样处理之前创建类该方法的代码。
因为该方法需要执行。(翻译不好)
Interfaces are defined using the interface keyword, in the same way as a standard class, but without any of the methods having their contents defined.
接口使用interface关键字定义,类似于标准的类,但没有定义任何方法的具体实现(有点儿像抽象类,但不同,我是这么认为的,抽象类中至少有一个方法要是抽象的,而接口中所有的方法都必须是抽象的。
而且接口是针对方法而引进的,而抽象类是在类的级别上引进的,所以我们说继承一个抽象类,而说实现一个接口。这是不同的,再有就是我认为--专家也这么认为,接口是为实现多继承而引入的)。
All methods declared in an interface must be public, this is the nature of an interface.
此外,接口中所有的方法都应该定义成public的,对于接口这是显然的。不然定义个private的接口干嘛使!
implements
To implement an interface, the implements operator is used. All methods in the interface must be implemented within a class; failure to do so will result in a fatal error. Classes may implement more than one interface if desired by separating each interface with a comma.
用implements关键字来执行接口。而且可以实现多个接口,之间用','号隔开。
Note: A class cannot implement two interfaces that share function names, since it would cause ambiguity.
注意:一个类不能实现两个有相同函数名的接口,因为那样会引起混淆。
范例
例子 19-17. Interface example
// 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;
   }
}
?>
九、超载(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型。
In PHP 5.0.x, all overloading methods must be defined as
public
.
在PHP 5.0.X中,所有的超载方法必须定义为public类型。
Since PHP 5.1.0 it is also possible to overload the
isset()
and
unset()
functions via the __isset and __unset methods respectively.
从PHP5.1.0起,isset()和unset() 也可以通过__isset和__unset方法被超载。
成员超载void __set ( string name, mixed value )
mixed __get ( string name )
bool __isset ( string name )
void __unset ( string name )
Class members can be overloaded to run custom code defined in your class by defining these specially named methods. The $name parameter used is the name of the variable that should be set or retrieved. The __set() method's $value parameter specifies the value that the object should set the $name.
类成员可以被超载用来运行客户定义的指定名字的方法。用__set()方法设定指定方法的名称和值,具体如下例。

Example 19-20. overloading with __get, __set, __isset and __unset example
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);
?>
The above example will output:
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 overloadingmixed __call ( string name, array arguments )
Class methods can be overloaded to run custom code defined in your class by defining this specially named method. The $name parameter used is the name as the function name that was requested to be used. The arguments that were passed in the function will be defined as an array in the $arguments parameter. The value returned from the __call() method will be returned to the caller of the method.
也就是说,php提供了__call()函数来返回你要调用的方法。就是你定义的特定名字的方法,如果没有,那么就会调用__call()方法,并把你的方法的名字做为第一个参数$name,而你的方法中的参量作为__call()的第二个参数$arguments(他通常定义为一个数组)。然后用__call()的执行体来作为你的特定的函数的执行体执行,他的返回结果作为你要的返回结果返回。
Example 19-21. overloading with __call example
class Caller
{
   private $x = array(1, 2, 3);
   private 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);
?>
The above example will output:
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提供了一种对于对象的可以进行循环操作列出其元素的途径。例如使用foreach,默认的,所有的可见属性都将用在循环中。(翻译不好,还是看例子吧)
Example 19-22. Simple Object Iteration
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();
?>
The above example will output:
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.
foreach循环只能显示可访问属性(public的)。更进一步,你可以执行php5的一个名为Iterator的内部接口。
他允许对象决定什么(what)及怎样(how)被循环/反复(iterate)
Example 19-23. 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";
}
?>
The above example will 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.
你还可以定义你的类,来通过执行php5的IteratorAggregate接口,而不必定义所有的Iterator接口的函数。
十一、模式(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. A Parameterized Factory receives the name of the class to instantiate as argument.

Example 19-25. Parameterized Factory Method
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');
       }
   }
}
?>
Defining this method in a class allows drivers to be loaded on the fly. If the Example class was a database abstraction class, loading a MySQL and SQLite driver could be done as follows:
// 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.
Example 19-26. Singleton Function
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);
   }
}
?>
This allows a single instance of the Example class to be retrieved.
// This would fail because the constructor is private
$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);
?>
十二、


相关阅读 更多 +
排行榜 更多 +
模拟梦幻人生 v2.0.1 安卓版

模拟梦幻人生 v2.0.1 安卓版

飞行射击 下载
模拟梦幻人生 v2.0.1 安卓版

模拟梦幻人生 v2.0.1 安卓版

飞行射击 下载
模拟梦幻人生 v2.0.1 安卓版

模拟梦幻人生 v2.0.1 安卓版

飞行射击 下载