[ Disponible en français ] 適当な訳:バスケ
新しいオブジェクトモデル
PrivateとProtectedメンバ変数
Privateとprotectedメソッド
抽象クラスとメソッド
インターフェース
クラス型のヒント
final
オブジェクトの複製(クローン)
Unified Constructors
Destructors
Constants
Exceptions
Dereferencing objects returned from functions
Static member variables of static classes can now be initialized
Static Methods
instanceof
Static function variables
Parameters that are passed by reference to a function may now have default values
__autoload()
Overloadable Method calls and Property accesses
イテレーション
New __METHOD__ constant
New __toString() method
Reflection API
新しくなったメモリ・マネージャ
PHPのオブジェクトの扱い方が一新され、速度が向上し、機能も追加されました。前のPHPのバージョンでは、オブジェクトは数値型や文字列型と同じように基本型として扱われていました。この方法だと変数に設定するときや関数に渡す場合に、オブジェクト全体をコピーすることになってしまっていました。そこで、こんどの新しいやり方では、ハンドル経由でオブジェクトを扱うことになりました(ハンドルとはオブジェクトを表す唯一のモノという感じの意味)。
ほとんどのPHPプログラマは、オブジェクトをコピーするという以前のPHPの習性さえも気づいていないでしょうから、ほとんどのPHPアプリケーションは、おそらくはそのまま、悪くてもほんの少しの習性で動作するでしょう。
ボクのコードではリファレンスを多用していたので、けっこう不安なところ。
PHP 5にはprivateとprotectedメンバ変数が導入されました。これによりクラス情報の可視性を定義できるようになります。
Protectedメンバ変数はそのクラスを継承したクラスからもアクセスすることが出来ますが、Privateメンバ変数はそのクラスそのものからしかアクセスできません。
<?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(); /* 表示される */
print "MyClass2::printHello() " . $this->Hello; /* 何も表示されない */
print "MyClass2::printHello() " . $this->Bar; /* 何も表示されない(未定義)*/
print "MyClass2::printHello() " . $this->Foo; /* 表示される */
}
}
$obj = new MyClass();
print $obj->Hello; /* 何も表示されない */
print $obj->Bar; /* 何も表示されない */
print $obj->Foo; /* 何も表示されない */
$obj->printHello(); /* 表示される */
$obj = new MyClass2();
print $obj->Hello; /* 何も表示されない */
print $obj->Bar; /* 何も表示されない */
print $obj->Foo; /* 何も表示されない */
$obj->printHello();
?>
PHP 5にはprivateとprotectedなメソッドも導入されています。
<?php
class Foo {
private function aPrivateMethod() {
echo "Foo::aPrivateMethod() が呼ばれた。\n";
}
protected function aProtectedMethod() {
echo "Foo::aProtectedMethod() が呼ばれた。\n";
$this->aPrivateMethod();
}
}
class Bar extends Foo {
public function aPublicMethod() {
echo "Bar::aPublicMethod() が呼ばれた。\n";
$this->aProtectedMethod();
}
}
$o = new Bar;
$o->aPublicMethod();
?>
"public", "protected", "private"といった名前でユーザー定義のクラスや関数を使っていなければ、昔のコードで問題となることはありません。
PHP 5には抽象クラスとメソッドが追加されています。抽象メソッドはメソッドのシグネチャのみを定義したもので、中身はありません。中傷メソッドを含むクラスは抽象クラスとして定義する必要があります。
<?php
abstract class AbstractClass {
abstract public function test();
}
class ImplementedClass extends AbstractClass {
public function test() {
echo "ImplementedClass::test() が呼ばれた。\n";
}
}
$o = new ImplementedClass;
$o->test();
?>
抽象クラスをインスタンス化することはできません。昔のコードで"abstruct"という名前のクラスや関数を使っていなければ問題ありません。
PHP 5では新しくインターフェースが導入されました。クラスはインターフェースの集合としても定義できます。
<?php
interface Throwable {
public function getMessage();
}
class MyException implements Throwable {
public function getMessage() {
// ...
}
}
?>
"interface"と"implements"という名前のユーザー定義クラスや関数を使っていなければ、昔のコードは問題ありません。
もとからある緩い型も今まで通り使えますが、PHP 5では新しくクラス型のヒントを記述することが出来るようになりました。これにより、メソッドが受け取る引数のオブジェクトのクラスを指定できるようになります。
<?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);
?>
他の型チェックをもった言語とは異なり、クラス型のヒントのチェックはコンパイル時ではなく実行時に行われます。つまり、
<?php
function foo(ClassName $object) {
// ...
}
?>
上記のコードは以下のコードと同等です。
<?php
function foo($object) {
if (!($object instanceof ClassName)) {
die("Argument 1 must be an instance of ClassName");
}
}
?>
この表記はクラス/オブジェクトについてのみ有効で、元からある型には使えません。
PHP 5 introduces the "final" keyword to declare final members and methods. Methods and members declared final cannot be overridden by sub-classes.
<?php
class Foo {
final function bar() {
// ...
}
}
?>
It is furthermore possible to make a class final. Doing this prevents a class from being specialized (it cannot be inherited by another class). There's no need to declare the methods of a final class themselves as final.
<?php
final class Foo {
// class definition
}
// the next line is impossible
// class Bork extends Foo {}
?>
Properties cannot be final.
Old code that has no user-defined classes or functions named 'final' should run without modifications.
PHP 4においては、オブジェクトが複製されるときに使われるコンストラクタをユーザーが指定することは出来ませんでした。コピーが行われる際にはPHP 4はビット単位で完全なるコピーを作成していたのです。
コピーの際に完全な属性の複製を行うということが常に望まれている動作というわけではありません。例えば、GTKウィンドウを表すオブジェクトがあったとして、オブジェクトはそのリソースを保持しているとします。 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, PHP 5 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.
<?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";
?>
PHP 5 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().
<?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();
?>
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.
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 named __destruct()
that receives no parameters, is called before the object is freed from memory.
<?php
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$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.
PHP 5 introduces per-class constants:
<?php
class Foo {
const constant = "constant";
}
echo "Foo::constant = " . Foo::constant . "\n";
?>
Old code that has no user-defined classes or functions named 'const' will run without modifications.
PHP 4 had no exception handling. PHP 5 introduces a exception model similar to that of other programming languages. Note that there is support for "catch all" but not for the "finally" clause.
Exceptions can be rethrown in catch blocks. Also it is possible to have multiple catch blocks. In that case the caught exception is compared with the classtype of each catch block from top to bottom and the first block that has an 'instanceof' match gets executed. When the catch block finishes, execution continues at the end of the last catch block. If no catch block has an 'instanceof' match then the next try/catch block is searched until no more try/catch blocks are available. In that case the exception is an uncaught exception and the program terminates with showing the exception.
<?php
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;
}
?>
Even though the above example shows that it is possible to define exception classes that don't inherit from Exception it is best to do so. This is because the internal Exception class can gather a lot of information otherwise not available. The PHP code emulation code would look something like shown below. The codecomments show the meaning of each property and hence their getter methods. As the code shows it is possible to read any available information by using the getter methods. But since some of the methods are used internally they are marked final. All in all the class is very restrictive because it must be ensured that anything used internally always works as expected.
<?php
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
}
}
?>
If you derive your exception classes from this Exception base class your exceptions will be nicely shown in the built-in handler for uncaught exceptions.
Old code that has no user-defined classes or functions 'catch', 'throw' and 'try' will run without modifications.
In PHP 4 it wasn't possible to dereference objects returned by functions and make further method calls on those objects. With PHP 5, the following is now possible:
<?php
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();
?>
<?php
class foo {
static $my_static = 5;
public $my_prop = 'bla';
}
print foo::$my_static;
$obj = new foo;
print $obj->my_prop;
?>
PHP 5 introduces the 'static' keyword to declare a method static, thus callable from outside the object context.
<?php
class Foo {
public static function aStaticMethod() {
// ...
}
}
Foo::aStaticMethod();
?>
The pseudo variable $this is not available inside a method
that has been declared static.
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.
<?php
class baseClass { }
$a = new baseClass;
if ($a instanceof baseClass) {
echo "Hello World";
}
?>
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.
<?php
function my_function(&$var = null) {
if ($var === null) {
die("$var needs to have a value");
}
}
?>
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.
<?php
function __autoload($className) {
include_once $className . ".php";
}
$object = new ClassName;
?>
Both method calls and property accesses can be overloaded via the
__call(), __get() and __set()
methods.
<?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: $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);
?>
<?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);
?>
オブジェクトをforeachを使って イテレートが出来るようになりました。この動作は上書き可能です。デフォルトの動作はオブジェクトのすべてのプロパティを順番に参照します。
<?php
class Foo {
var $x = 1;
var $y = 2;
}
$obj = new Foo;
foreach ($obj as $prp_name => $prop_value) {
// using the property
}
?>
インスタンスがforeachでイテレートできるようなクラスを作るには、空のインターフェースであるTraversableをインプリメントしなくてはいけません。つまり、Traversableをインプリメントしていると宣言しているオブジェクトはforeachで使えるということになります。
IteratorAggregateインターフェースとIteratorインターフェースを使うと、クラスのオブジェクトをどのようにイテレートするかを指定することが出来ます。前者はgetIterator()というたった一つのメソッドをを持ちます。このメソッドは、配列を返すかIteratorインターフェースをインプリメントしたオブジェクトを返さなければいけません。この場合、PHPが内部的に定義したイテレートできるクラスのオブジェクトでも構いません。
<?php
class ObjectIterator implements Iterator {
private $obj;
private $num;
function __construct($obj) {
$this->obj = $obj;
}
function rewind() {
$this->num = 0;
}
function hasMore() {
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);
?>
この例では、IteratorインターフェースとIteratorAggregateインターフェースのすべての抽象メソッドを定義してある。
__METHOD__ constant
The new __METHOD__ pseudo constant shows the current class
and method when used inside a method and the function when used outside of a
class.
<?php
class Foo {
function Show() {
echo __FILE__ . '(' . __LINE__ . ')' . __METHOD__;
}
}
function Test() {
echo __FILE__ . '(' . __LINE__ . ')' . __METHOD__;
}
?>
__toString() method
The new __toString() magic method allows you to overload the
object to string conversion.
<?php
class Foo {
function __toString() {
return "What ever";
}
}
$obj = Foo;
$str = (string) $obj; // call __toString()
echo $obj; // call __toString()
?>
PHP 5 comes with a complete reflection API that adds the ability to reverse-engineer classes, interfaces, functions and methods as well as extensions.
The reflection API also offers ways of getting doc codecomments for functions, classes and methods.
Nearly all aspects of object oriented code can be reflected by using the reflection API which is documented separately.
<?php
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');
?>
PHP 5には新しいメモリ・マネージャを備わりました。メモリの確保/解放の時にmutexを使わないので、マルチスレッド環境において効率的に動作します。