热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHP5新特性:更加面向对象化的PHP

PHP5新特性:更加面向对象化的PHP
PHP处理对象部分的内核完全重新开发过,提供更多功能的同时也提高了性能。在以前版本的php中,处理对象和处理基本类型(数字,字符串)的方式是一样的。这种方式的缺陷是:当将对象赋值给一个变量时,或者通过参数传递对象时,对象将被完全拷贝一份。在新的版本里,上述操作将传递引用(可以把引用理解成对象的标识符),而非值。

很多PHP程序员可能甚至没有察觉到老的对象处理方式。事实上,大多数的php应用都可以很好地运行。或者仅仅需要很少的改动。

私有和受保护成员
PHP5引入了私有和受保护成员变量的概念。我们可以用它来定义类成员的可见性。

例子
受保护成员可以被子类访问, 而私有成员只能被类本身访问。

class MyClass {
private $Hello = "Hello, World!\n";
protected $Bar = "Hello, Foo!\n";
protected $Foo = "Hello, Bar!\n";

function printHello() {
print "MyClass::printHello() " . $this->Hello;
print "MyClass::printHello() " . $this->Bar;
print "MyClass::printHello() " . $this->Foo;
}
}

class MyClass2 extends MyClass {
protected $Foo;

function printHello() {
MyClass::printHello(); /* Should print */
print "MyClass2::printHello() " . $this->Hello; /* Shouldn't print out anything */
print "MyClass2::printHello() " . $this->Bar; /* Shouldn't print (not declared)*/
print "MyClass2::printHello() " . $this->Foo; /* Should print */
}
}

$obj = new MyClass();
print $obj->Hello; /* Shouldn't print out anything */
print $obj->Bar; /* Shouldn't print out anything */
print $obj->Foo; /* Shouldn't print out anything */
$obj->printHello(); /* Should print */

$obj = new MyClass2();
print $obj->Hello; /* Shouldn't print out anything */
print $obj->Bar; /* Shouldn't print out anything */
print $obj->Foo; /* Shouldn't print out anything */
$obj->printHello();
?>

私有方法和受保护方法
PHP5也引入了私有方法和受保护方法的概念。

例子:
class Foo {
private function aPrivateMethod() {
echo "Foo::aPrivateMethod() called.\n";
}

protected function aProtectedMethod() {
echo "Foo::aProtectedMethod() called.\n";
$this->aPrivateMethod();
}
}

class Bar extends Foo {
public function aPublicMethod() {
echo "Bar::aPublicMethod() called.\n";
$this->aProtectedMethod();
}
}

$o = new Bar;
$o->aPublicMethod();
?>

以前的不使用类的老代码,没有访问修饰符(public, protected, private)的代码可以不经改动运行。

抽象类和抽象方法
Php5也引入了抽象类和抽象方法的概念。抽象方法只是声明了方法的签名并不提供它的实现。包含抽象方法的类必须被声明成抽象类。

例子:
abstract class AbstractClass {
abstract public function test();
}

class ImplementedClass extends AbstractClass {
public function test() {
echo "ImplementedClass::test() called.\n";
}
}

$o = new ImplementedClass;
$o->test();
?>

抽象类不能被实例化。以前的不使用抽象类的老代码可以不经改动运行。

接口
Php5引入了接口。一个类可以实现多个接口。

例子:
interface Throwable {
public function getMessage();
}

class MyException implements Throwable {
public function getMessage() {
// ...
}
}
?>

以前的不使用接口的老代码可以不经改动运行



类的型别提示

PHP5依然是弱类型的,不过在定义函数参数时,可以使用类的型别提示来声明期望传入的对象类型

Example
interface Foo {
function a(Foo $foo);
}

interface Bar {
function b(Bar $bar);
}

class FooBar implements Foo, Bar {
function a(Foo $foo) {
// ...
}

function b(Bar $bar) {
// ...
}
}

$a = new FooBar;
$b = new FooBar;

$a->a($b);
$a->b($b);
?>

和其他强类型语言一样,php5类的型别提示在运行期间检查而非编译期间检查。即:

function foo(ClassName $object) {
// ...
}
?>

和下面的代码是一样的:

function foo($object) {
if (!($object instanceof ClassName)) {
die("Argument 1 must be an instance of ClassName");
}
}
?>

这个语法只适用于类,不适用于内建类型。

Final

PHP 5 引入了final关键字来声明final成员和final方法。final成员和final方法不能被子类覆盖。

Example
class Foo {
final function bar() {
// ...
}
}
?>

更进一步,可以把类声明成final。将类声明成final可以阻止这个类被继承。final类里面的方法缺省地都是final的,无需再声明一次。

Example
final class Foo {
// class definition
}

// the next line is impossible
// class Bork extends Foo {}
?>

属性不能定义成为final.

以前的不使用final的老代码可以不经改动运行.

对象克隆
Php4没有提供一种机制来让用户自己定义复制构造子(copy constructor)控制对象的复制过程。Php4做二进制的拷贝,因而很精确地复制了对象的所有属性。

精确地复制对象的所有属性可能并不是我们一直想要的。有个例子可以很好地说明我们确实需要复制构造子:比如一个GTK Window的对象 a。 a持有它所需要的全部资源。当复制的这个GTK Window到对象b时候,我们更希望b持有新的资源对象。再举个例子:对象a包含了一个对象c, 当你把对象a 复制到对象c的时候。我们可能更希望对象b包含一个新的对象c的copy, 而不是一个对象c的引用。(译者注:这里所说的就是浅克隆和深克隆。)

对象的复制是通过clone这个关键字达到的(Clone调用被克隆对象的__clone()方法)。对象的__clone方法不能够直接被调用。

$copy_of_object = clone $object;
?>

当developer创建对象的一份拷贝的时候,php5将会检查 __clone()方法是否存在。如果不存在,那么它就会呼叫缺省的__clone()方法,复制对象的所有属性。如果__clone()方法已经定义过,那么_clone()方法就会负责设置新对象的属性。为了方便起见,Engine会缺省地复制所有的属性。所以在__clone()方法中,只需要覆盖那些需要更改的属性就可以了。如下:
Example
class MyCloneable {
static $id = 0;

function MyCloneable() {
$this->id = self::$id++;
}

function __clone() {
$this->address = "New York";
$this->id = self::$id++;
}
}

$obj = new MyCloneable();

$obj->name = "Hello";
$obj->address = "Tel-Aviv";

print $obj->id . "\n";

$obj_clOned= clone $obj;

print $obj_cloned->id . "\n";
print $obj_cloned->name . "\n";
print $obj_cloned->address . "\n";
?>

统一构造函数
Php5允许开发者声明一个类的构造方法。拥有构造方法的类在每次创建新的对象的时候都会呼叫这个方法,因此构造方法适合对象在被使用之前的初始化工作

Php4中,构造方法的名称和类的名称一样。考虑到从子类构造方法呼叫父类构造方法的情况是非常普遍的,而将类从一个继承体系中搬迁引起的父类变更就常常导致需要更改类的构造方法,php4的做法显然是不太合理的。

Php5引入了一个声明构建函数的标准方法: __construct().如下:

Example
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();
?>

为保持向后的兼容性,如果php5不能够找到 __construct(),它会寻找老式的构造方法,即与类同名的方法。简单的说,只有当老代码里包含了一个__construct()方法的时候,才存在一个兼容性的问题。

析构方法
对于面向对象的编程来说,可以定义析构方法是非常有用的一个功能。析构方法可以用来记录调试信息,关闭数据库连接等等一些清除收尾的工作。Php4中没有析构方法,尽管php4已经支持可以注册一个函数以便请求结束的时候被调用。

Php5引进的析构方法的概念和其他面向对象的语言(比如java)是一致的。当指向这个对象的最后一个引用被销毁的时候,析构方法被调用,调用完成后释放内存。注意:析构方法不接受任何参数。

Example
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}

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

$obj = new MyDestructableClass();
?>

和构建方法一样,父类的析构方法也不会被隐含调用。子类可以在自己的析构方法通过调用parent::__destruct()来显式地调用它。

Constants
Php5引入了class级别的常量。

class Foo {
const cOnstant= "constant";
}

echo "Foo::cOnstant= " . Foo::constant . "\n";
?>

老的没有使用const的代码仍然正常运行。

Exceptions
Php4没有异常控制。Php5引入了和其它语言(java)相似的异常控制模式。应该注意的是php5里面支持捕捉全部异常,但是不支持finally子句。

在catch语句块里面,可以重新抛出异常。也可以有多个catch语句,在这种情况下,被捕捉到的异常从上往下依次比较和catch语句比较异常,第一个类型匹配的catch语句将会被执行。如果一直搜索到底还没有发现匹配的catch子句,则寻找下一个try/catch语句。最后不能捕捉的异常将被显示出来。如果异常被捕捉,那么程序会接着catch语句块的下面开始执行。

Example
class MyException {
function __construct($exception) {
$this->exception = $exception;
}

function Display() {
print "MyException: $this->exception\n";
}
}

class MyExceptionFoo extends MyException {
function __construct($exception) {
$this->exception = $exception;
}

function Display() {
print "MyException: $this->exception\n";
}
}

try {
throw new MyExceptionFoo('Hello');
}
catch (MyException $exception) {
$exception->Display();
}
catch (Exception $exception) {
echo $exception;
}
?>

上面的例子表明可以定义一个并不继承自 Exception的异常类,但是,最好还是从Exception继承并定义自己的异常。这是因为系统内建的Exception类能够收集到很多有用的信息, 而不继承它的异常类是得不到这些信息的。下面的php代码模仿了系统内建Exception类。每个属性后面都加了注释。每个属性都有一个getter,由于这些getter方法经常被系统内部处理调用,所以这些方法被标明了final。

Example
class Exception {
function __construct(string $message=NULL, int code=0) {
if (func_num_args()) {
$this->message = $message;
}
$this->code = $code;
$this->file = __FILE__; // of throw clause
$this->line = __LINE__; // of throw clause
$this->trace = debug_backtrace();
$this->string = StringFormat($this);
}

protected $message = 'Unknown exception'; // exception message
protected $code = 0; // user defined exception code
protected $file; // source filename of exception
protected $line; // source line of exception

private $trace; // backtrace of exception
private $string; // internal only!!

final function getMessage() {
return $this->message;
}
final function getCode() {
return $this->code;
}
final function getFile() {
return $this->file;
}
final function getTrace() {
return $this->trace;
}
final function getTraceAsString() {
return self::TraceFormat($this);
}
function _toString() {
return $this->string;
}
static private function StringFormat(Exception $exception) {
// ... a function not available in PHP scripts
// that returns all relevant information as a string
}
static private function TraceFormat(Exception $exception) {
// ... a function not available in PHP scripts
// that returns the backtrace as a string
}
}
?>

如果我们定义的一异常类都是继承自Exception基类

无兼容性问题。老的代码不会受到这一特性的影响。

Dereferencing objects returned from functions
Php4中不能再次引用函数返回的对象以进一步呼叫返回对象的方法,而php5是可以的。

class Circle {
function draw() {
print "Circle\n";
}
}

class Square {
function draw() {
print "Square\n";
}
}

function ShapeFactoryMethod($shape) {
switch ($shape) {
case "Circle":
return new Circle();
case "Square":
return new Square();
}
}

ShapeFactoryMethod("Circle")->draw();
ShapeFactoryMethod("Square")->draw();
?>

静态成员变量能够被初始化。
Example
class foo {
static $my_static = 5;
public $my_prop = 'bla';
}

print foo::$my_static;
$obj = new foo;
print $obj->my_prop;
?>

静态方法
PHP 5 引入了静态方法,可以在不实例化类的情况下呼叫静态方法。

Example
class Foo {
public static function aStaticMethod() {
// ...
}
}

Foo::aStaticMethod();
?>

伪变量$this不能够在静态方法方法中使用。

instanceof
Php5引入了instanceof关键字,允许用它来测试一个对象是一个类的实例,或者是一个派生类的实例,或者实现了某个接口

Example
class baseClass { }

$a = new baseClass;

if ($a instanceof baseClass) {
echo "Hello World";
}
?>

Static function variables
现在,静态变量在编译阶段处理。因此程序员可以通过引用为静态变量赋值。这可以改善性能,不过,不能够使用对静态变量的间接引用了。

按引用传递的函数参数现在也可以设置缺省值了。

Example
function my_function(&$var = null) {
if ($var === null) {
die("$var needs to have a value");
}
}
?>

__autoload()
__autoload() 拦截函数在一个未声明的类被初始化的时候自动调用。该类的名字会被自动传递给__autoload()函数。而__autoload()也只有这么唯一的一个参数。

Example
function __autoload($className) {
include_once $className . ".php";
}

$object = new ClassName;
?>

可重载的方法呼叫和属性访问
方法呼叫和属性访问都能够通过__call, __get() and __set()方法重载。

Example: __get() and __set()
class Setter {
public $n;
public $x = array("a" => 1, "b" => 2, "c" => 3);

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

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

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

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

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

Example: __call()
class Caller {
private $x = array(1, 2, 3);

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

迭代
当和foreach一起使用对象的时候,迭代的方式被重载过了。缺省的行为是迭代类的所有属性。

Example
class Foo {
public $x = 1;
public $y = 2;
}

$obj = new Foo;

foreach ($obj as $prp_name => $prop_value) {
// using the property
}
?>

一个类的所有对象都能够被迭代浏览到, 如果这个类实现了一个空的接口:Traversable. 换句话说,实现了Traversable接口的类可以和foreach一起使用。

接口 IteratorAggregate 和Iterator允许指定类的对象在代码中如何迭代。IteratorAggregate接口有一个方法:getIterator() 必须返回一个数组

Example
class ObjectIterator implements Iterator {

private $obj;
private $num;

function __construct($obj) {
$this->obj = $obj;
}
function rewind() {
$this->num = 0;
}
function valid() {
return $this->num <$this->obj->max;
}
function key() {
return $this->num;
}
function current() {
switch($this->num) {
case 0: return "1st";
case 1: return "2nd";
case 2: return "3rd";
default: return $this->num."th";
}
}
function next() {
$this->num++;
}
}

class Object implements IteratorAggregate {

public $max = 3;

function getIterator() {
return new ObjectIterator($this);
}
}

$obj = new Object;

// this foreach ...
foreach($obj as $key => $val) {
echo "$key = $val\n";
}

// matches the following 7 lines with the for directive.
$it = $obj->getIterator();
for($it->rewind(); $it->hasMore(); $it->next) {
$key = $it->current();
$val = $it->key();
echo "$key = $val\n";
}
unset($it);
?>

新的__toString方法
可以通过覆盖__toString方法来控制对象到字符串的转换。

Example
class Foo {
function __toString() {
return "What ever";
}
}

$obj = new Foo;

echo $obj; // call __toString()
?>

Reflection API
Php5引入了全套的反射API,以支持对类,接口,函数,方法的反向工程。

它也提供了API以从程序中提取注释文档。反射API的详细资料参考此处:http://sitten-polizei.de/php/reflection_api/docs/language.reflection.html

Example
class Foo {
public $prop;
function Func($name) {
echo "Hello $name";
}
}

reflection_class::export('Foo');
reflection_object::export(new Foo);
reflection_method::export('Foo', 'func');
reflection_property::export('Foo', 'prop');
reflection_extension::export('standard');
?>

新内存管理机制
Php5有一个全新的内存管理机制,使得它在多线程的环境下可以更有效地运行。在分配和释放内存时,不再使用mutex锁定/解除锁定
推荐阅读
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文是一位90后程序员分享的职业发展经验,从年薪3w到30w的薪资增长过程。文章回顾了自己的青春时光,包括与朋友一起玩DOTA的回忆,并附上了一段纪念DOTA青春的视频链接。作者还提到了一些与程序员相关的名词和团队,如Pis、蛛丝马迹、B神、LGD、EHOME等。通过分享自己的经验,作者希望能够给其他程序员提供一些职业发展的思路和启示。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
author-avatar
公安边防临高支队警务微博_821
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有