Changes in PHP 5/Zend Engine 2.0 (转)

本文详细介绍了PHP5中引入的重要新特性,包括改进的对象模型、私有和受保护成员、抽象类和方法、接口、类型提示等。同时,还探讨了统一构造函数、析构函数、异常处理、静态成员变量及方法等关键概念。
Changes in PHP 5/Zend Engine 2.0 (转)[@more@]

Changes in PHP 5/zend Engine 2.0

New object Model.

PHP's handling of objects has been completely rewritten, allowing for better performance and more features. In previous versions of PHP, objects were handled like primitive types (for instance integers and strings). The drawback of this method was that semantically the whole object was copied when a variable was assigned, or pass as a parameter to a method. In the new approach, objects are referenced by handle, and not by value (one can think of a handle as an object's identifier).

Many PHP programmers aren't even aware of the copying quirks of the old object model and, therefore, the majority of PHP applications will work out of the box, or with very few modifications.

Private and Protected Members

PHP 5 introduces private and protected member variables, they allow do define the visibility of class properties.

Example

Protected member variables can be accessed in classes extending the class they are declared in, whereas private member variables can only be accessed by the class they belong to.

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

Private and protected methods

With PHP 5 (Zend Engine 2), private and protected methods are also introduced.

Example

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

Old code that has no user-defined classes or functions named "public," "protected" or "private" should run without modifications.

Abstract Classes and Methods

PHP 5 also introduces abstract classes and methods. An abstract method only declares the method's signature and does not provide an implementation. A class that contains abstract methods needs to be declared abstract.

Example

<?php
abstract class AbstractClass {
 abstract public function test();
}

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

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

Abstract classes cannot be instantiated. Old code that has no user-defined classes or functions named 'abstract' should run without modifications.

Interfaces

The Zend Engine 2.0 introduces interfaces. A class may implement an arbitrary list of interfaces.

Example

<?php
interface Throwable {
 public function getMessage();
}

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

Old code that has no user-defined classes or functions named 'interface' or 'implements' should run without modifications.

Class Type Hints

While remaining loosely typed PHP 5 introduces the ability to use class type hints to declare the expected class of objects that are passed as parameters to a method.

Example

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

These class type hints are not checked upon compilation, as would be the case in a typed language, but during runtime. This means that:

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

is equivalent to:

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

This syntax only applies to objects/classes, not built-in types.

final

PHP 5 introduces the "final" keyword to declare final members and methods. Methods and members declared final cannot be overridden by sub-classes.

Example

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

Old code that has no user-defined classes or functions named 'final' should run without modifications.

Object Cloning

PHP 4 (Zend Engine 1.0) offered no way a user could decide what copy constructor to run when an object is duplicated. During duplication, PHP 4 did a bit for bit copy making an identical replica of all the object's properties.

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 calling the object's __clone() method:

<?php
$copy_of_object = $object->__clone();
?>

When the developer asks to create a new copy of an object, the Zend Engine will check if a __clone() method has been defined or not. If not, it will call a default __clone() which will copy all of the object's properties. If a __clone() method is defined, then it will be responsible to set the necessary properties in the created object. For convenience, the engine will supply a function that imports all of the properties from the source object, so that they can start with a by-value replica of the source object, and only override properties that need to be changed.

Example

<?php
class MyCloneable {
 static $id = 0;

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

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

$obj = new MyCloneable();

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

print $obj->id . "n";

$obj = $obj->__clone();

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

Unified Constructors

The Zend Engine allows developers to declare constructor methods for classes. Classes which have a constructor method call this method on each newly-created object, so it is suitable for any initialization that the object may need before it is used.

With PHP 4, constructor methods were class methods that had the same name as the class itself. Since it is very common to call parent constructors from derived classes, the way PHP 4 worked made it a bit cumbersome to move classes around in a large class hierarchy. If a class is moved to reside under a different parent, the constructor name of that parent changes as well, and the code in the derived class that calls the parent constructor has to be modified.

PHP 5 introduces a standard way of declaring constructor methods by calling them by the name __construct().

Example

<?php
class BaseClass {
 function __construct() {
 print "In BaseClass constructorn";
 }
}

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

$obj = new BaseClass();
$obj = new SubClass();
?>

For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class. Effectively, it means that the only case that would have compatibility issues is if the class had a method named __construct() which was used for different semantics.

Destructors

Having the ability to define destructors for objects can be very useful. Destructors can log messages for debugging, close database connections and do other clean-up work. No mechanism for object destructors existed in PHP 4, although PHP had already support for registering functions which should be run on request shutdown.

PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as Java: When the last reference to an object is destroyed the object's destructor, which is a class method name %__destruct()% that recieves no parameters, is called before the object is freed from memory.

Example

<?php
class MyDestructableClass {
 function __construct() {
 print "In constructorn";
 $this->name = "MyDestructableClass";
 }

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

$obj = new MyDestructableClass();
?>

Like constructors, parent destructors will not be called implicitly by the engine. In order to run a parent destructor, one would have to explicitly call parent::__destruct() in the destructor body.

Constants

PHP 5 introduces per-class constants:

<?php
class Foo {
 const constant = "constant";
}

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

PHP 5 allows for expressions within constants, however, constants are evaluated at compile time, therefore no constants can be declared that rely on runtime information.

<?php
class Bar {
 const a = 1<<0;
 const b = 1<<1;
 const c = a | b;
}
?>

Old code that has no user-defined classes or functions named 'const' will run without modifications.

Exceptions

PHP 4 had no exception handling. PHP 5 introduces a exception model similar to that of other programming languages.

Example

<?php
class MyExceptionFoo extends Exception {
 function __construct($exception) {
 parent::__construct($exception);
 }
}

try {
 throw new MyExceptionFoo("Hello");
} catch (MyException $exception) {
 print $exception->getMessage();
}
?>

Old code that has no user-defined classes or functions 'catch', 'throw' and 'try' will run without modifications.

Dereferencing objects returned from functions

In PHP 4 it wasn't possible to dereference objects returned by functions and make further method calls on those objects. With the advent of Zend Engine 2, the following is now possible:

<?php
class Circle {
 function draw() {
 print "Circlen";
 }
}
 
class Square {
 function draw() {
 print "Squaren";
 }
}

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

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

Static member variables of static classes can now be initialized

Example

<?php
class foo {
 static $my_static = 5;
}

print foo::$my_static;
?>

Static Methods

PHP 5 introduces the 'static' keyword to declare a method static, thus callable from outside the object context.

Example

<?php
class Foo {
 public static function aStaticMethod() {
 // ...
 }
}

Foo::aStaticMethod();
?>

The pseudo variable $this is not available inside a method that has been declared static.

instanceof

PHP 5 introduces the instanceof keyword, that allows you to ascertain whether or not an object is an instance of a class, or extends a class, or implements an interface.

Example

<?php
class baseClass { }

$a = new baseClass;

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

Static function variables

Statics are now treated at compile-time which allows developers to assign variables to statics by reference. This change also greatly improves their performance but means that indirect references to statics will not work anymore.

Parameters that are passed by reference to a function may now have default values

Example

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

__autoload()

The __autoload() interceptor function will be automatically called when an undeclared class is to be instantiated. The name of that class will be passed to the __autoload() interceptor function as its only argument.

Example

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

$object = new ClassName;
?>

Overloadable Method calls and Property accesses

Both method calls and property accesses can be overloaded via the __call(), __get() and __set() methods.

Example: __get() and __set()

<?php
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: $rn";
 return $r;
 } else {
 print "Nothing!n";
 }
 }

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

 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()

<?php
class Caller {
 var $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);
?>

XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" />

 

 


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-997972/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-997972/

<think>我们正在讨论Git推送时出现的错误。用户上次询问了关于`git push origin HEAD:refs/for/FRC2.0`命令报错'remote rejected (no new changes)'的问题。根据错误信息,远程仓库拒绝了推送,因为提交的内容没有新的更改。 可能的原因和解决办法: 1. 本地没有新的提交:如果最近一次提交已经被推送过,或者当前分支没有新的提交,那么再次推送相同的提交就会触发这个错误。 解决办法:确认是否有新的提交(使用`git log`查看),如果没有,需要先创建新的提交再推送。 2. 使用了`--amend`修改了上一次提交:如果使用`git commit --amend`修改了上一次提交,那么原本的提交会被替换,导致再次推送时远程仓库认为没有变化(因为新的提交和之前的提交有相同的父提交,但内容不同,然而如果修改后的提交与上一次提交内容相同,则可能被拒绝)。 解决办法:如果确实需要推送修改后的提交,可以使用强制推送(注意:强制推送会覆盖远程分支,需谨慎使用)。但在这里,由于推送的目标引用是`refs/for/FRC2.0`(这是一个Gerrit系统的特殊引用,用于代码审核),所以强制推送可能不被允许或者不推荐。通常,Gerrit会为每个推送生成一个新的变更集,所以重新推送一个修改后的提交应该使用相同的命令,而不需要强制。但是,如果Gerrit中已经存在同一个变更的旧版本,并且你想要更新它,那么你只需要推送修改后的提交(不需要强制),Gerrit会将其关联到同一个变更上。然而,如果推送的是完全相同的提交(即内容哈希相同),则会被拒绝。 3. 本地分支与远程分支完全同步:即本地没有任何新的提交,此时再次推送就会报错。 解决办法:进行一些修改并提交,然后再推送。 4. 重复推送同一个提交:有时候,可能因为网络问题重复推送,但第一次推送已经成功,第二次就会报错。 解决办法:检查远程分支是否已经包含该提交(通过Gerrit的Web界面查看变更)。 5. Gerrit的配置:Gerrit要求每次推送到`refs/for/<branch>`的提交都必须是一个新的变更集(即一个新的提交),或者是对已有变更集的修订(这时提交必须有Change-Id,并且与已有变更集匹配)。如果提交信息中没有Change-Id,或者Change-Id与已有变更集不匹配,也可能导致问题。但通常,错误信息不是这个。 针对错误信息'remote rejected (no new changes)',重点在于没有新的更改。 步骤: 1. 首先,检查本地是否有未提交的更改:`git status` 2. 检查本地最近的提交:`git log -1` 查看最近一次提交的详细信息。 3. 检查Gerrit上是否已经存在该提交:可以通过Gerrit的Web界面查看。 4. 如果确实没有新的更改,那么需要创建新的提交: - 修改代码或文件 - `git add <file>` 或 `git add .` - `git commit` 创建新的提交 5. 再次尝试推送:`git push origin HEAD:refs/for/FRC2.0` 注意:如果之前使用`git commit --amend`修改了提交,并且该提交已经推送到Gerrit,那么再次推送修改后的提交是允许的(前提是修改后的提交确实有变化),Gerrit会将其作为原变更的新补丁集。但是,如果修改后的提交和原提交内容完全相同(即没有做任何修改),那么就会被拒绝。 如果确认有新的更改,但推送仍然被拒绝,可以尝试检查Gerrit的配置,或者查看推送命令是否正确。 另外,确保你的提交信息中包含Change-Id(Gerrit的commit-msg hook会自动添加)。如果没有安装hook,可能会导致Change-Id缺失,从而无法更新已有的变更。但通常错误信息会不同(例如缺少Change-Id)。 如果问题仍然存在,可以检查Gerrit的日志或者联系Gerrit管理员。 相关问题: 1. 如何安装Gerrit的commit-msg hook以避免Change-Id缺失的问题? 2. 在Gerrit中,如何更新一个已经推送的变更? 3. 使用Git时,如何查看远程分支的状态? </think>### Git推送错误解决方法 当使用命令 `git push origin HEAD:refs/for/FRC2.0` 出现 `remote rejected (no new changes)` 错误时,通常表示您尝试推送的提交与远程仓库中的现有内容完全一致。以下是系统化的解决方案: #### 1. **检查本地修改状态** ```bash git status ``` - **若无修改**:工作区干净(显示 `nothing to commit`),说明没有新内容可推送 - **若有修改**:先提交修改: ```bash git add . git commit -m "添加新修改" ``` #### 2. **强制生成新提交ID** 如果提交内容相同但因元数据不同需强制更新: ```bash git commit --amend --no-edit # 保留原提交信息但更新提交时间戳 git push origin HEAD:refs/for/FRC2.0 ``` #### 3. **验证Gerrit系统特殊要求** Gerrit代码审核系统对该错误有特殊处理: - 检查提交是否包含有效的 `Change-Id` - 确认 `.git/hooks/commit-msg` 钩子已安装(自动生成Change-Id) - 通过网页端确认变更是否已存在(URL通常为 `gerrit.your-company.com/q/FRC2.0`) #### 4. **添加空提交(慎用)** 仅用于触发流水线等特殊场景: ```bash git commit --allow-empty -m "触发CI构建" git push origin HEAD:refs/for/FRC2.0 ``` #### 5. **检查分支关联** 确认本地分支与远程引用匹配: ```bash git branch -vv # 验证跟踪关系 git push origin HEAD:refs/for/FRC2.0 --force # 非必要不使用强制推送 ``` > **关键提示**:在Gerrit体系中,推送到 `refs/for/` 的提交会生成新补丁集(patchset),若内容未改变系统将拒绝更新[^Gerrit-Docs]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值