- 实现了 StaticPropertyFetch 类型检查方法 - 扩展了 ClassDef 构造函数以支持 flags 参数 - 添加了类继承时对 final 类的检查逻辑 - 更新了示例文件 call3.php 中的类结构 - 增加了多个类相关的测试用例文件 - 修改了后置操作解析逻辑以支持静态属性访问 - 在编译器基类中添加了类声明的错误处理 - 实现了对象包装器数组初始化 - 添加了对类可见性构造函数的支持测试 - 更新了接口定义的构造函数实现pull/1/head
parent
4ed56de30e
commit
25e567b3db
19 changed files with 614 additions and 17 deletions
@ -1,21 +1,33 @@ |
|||||||
<?php |
<?php |
||||||
class C |
|
||||||
|
class Circle |
||||||
{ |
{ |
||||||
function __call($name, $values) |
function draw() |
||||||
{ |
{ |
||||||
$values[0][0] = 'changed'; |
echo "Circle\n"; |
||||||
} |
} |
||||||
} |
} |
||||||
function main() { |
|
||||||
$a = array('original'); |
|
||||||
$b = array('original'); |
|
||||||
|
|
||||||
$hack =& $b[0]; |
|
||||||
|
|
||||||
$c = new C; |
class Square |
||||||
$c->f($a); |
{ |
||||||
$c->f($b); |
function draw() |
||||||
|
{ |
||||||
|
print "Square\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
var_dump($a, $b); |
function ShapeFactoryMethod($shape) |
||||||
|
{ |
||||||
|
switch ($shape) { |
||||||
|
case "Circle": |
||||||
|
return new Circle(); |
||||||
|
case "Square": |
||||||
|
return new Square(); |
||||||
|
} |
||||||
} |
} |
||||||
|
|
||||||
|
function main() |
||||||
|
{ |
||||||
|
ShapeFactoryMethod("Circle")->draw(); |
||||||
|
ShapeFactoryMethod("Square")->draw(); |
||||||
|
} |
||||||
@ -0,0 +1,84 @@ |
|||||||
|
--TEST-- |
||||||
|
Classes general test |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
/* pretty nifty object-oriented code! */ |
||||||
|
|
||||||
|
class user { |
||||||
|
public $first_name,$family_name,$address,$phone_num; |
||||||
|
function display() |
||||||
|
{ |
||||||
|
echo "User information\n"; |
||||||
|
echo "----------------\n\n"; |
||||||
|
echo "First name:\t ".$this->first_name."\n"; |
||||||
|
echo "Family name:\t ".$this->family_name."\n"; |
||||||
|
echo "Address:\t ".$this->address."\n"; |
||||||
|
echo "Phone:\t\t ".$this->phone_num."\n"; |
||||||
|
echo "\n\n"; |
||||||
|
} |
||||||
|
function initialize($first_name,$family_name,$address,$phone_num) |
||||||
|
{ |
||||||
|
$this->first_name = $first_name; |
||||||
|
$this->family_name = $family_name; |
||||||
|
$this->address = $address; |
||||||
|
$this->phone_num = $phone_num; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
function test($u) |
||||||
|
{ /* one can pass classes as arguments */ |
||||||
|
$u->display(); |
||||||
|
$t = $u; |
||||||
|
$t->address = "New address..."; |
||||||
|
return $t; /* and also return them as return values */ |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
$user1 = new user; |
||||||
|
$user2 = new user; |
||||||
|
|
||||||
|
$user1->initialize("Zeev","Suraski","Ben Gourion 3, Kiryat Bialik, Israel","+972-4-8713139"); |
||||||
|
$user2->initialize("Andi","Gutmans","Haifa, Israel","+972-4-8231621"); |
||||||
|
$user1->display(); |
||||||
|
$user2->display(); |
||||||
|
|
||||||
|
$tmp = test($user2); |
||||||
|
$tmp->display(); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
User information |
||||||
|
---------------- |
||||||
|
|
||||||
|
First name: Zeev |
||||||
|
Family name: Suraski |
||||||
|
Address: Ben Gourion 3, Kiryat Bialik, Israel |
||||||
|
Phone: +972-4-8713139 |
||||||
|
|
||||||
|
|
||||||
|
User information |
||||||
|
---------------- |
||||||
|
|
||||||
|
First name: Andi |
||||||
|
Family name: Gutmans |
||||||
|
Address: Haifa, Israel |
||||||
|
Phone: +972-4-8231621 |
||||||
|
|
||||||
|
|
||||||
|
User information |
||||||
|
---------------- |
||||||
|
|
||||||
|
First name: Andi |
||||||
|
Family name: Gutmans |
||||||
|
Address: Haifa, Israel |
||||||
|
Phone: +972-4-8231621 |
||||||
|
|
||||||
|
|
||||||
|
User information |
||||||
|
---------------- |
||||||
|
|
||||||
|
First name: Andi |
||||||
|
Family name: Gutmans |
||||||
|
Address: New address... |
||||||
|
Phone: +972-4-8231621 |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 A final class cannot be inherited |
||||||
|
--SKIPIF-- |
||||||
|
<?php die('skip'); ?> |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
final class base { |
||||||
|
function show() { |
||||||
|
echo "base\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class derived extends base { |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
$t = new base(); |
||||||
|
echo "Done\n"; // shouldn't be displayed |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECTF-- |
||||||
|
Fatal error: Class derived cannot extend final class base in %s on line %d |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
--TEST-- |
||||||
|
Instantiate stdClass |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
function main() { |
||||||
|
$obj = new stdClass; |
||||||
|
echo get_class($obj)."\n"; |
||||||
|
echo "Done\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
stdClass |
||||||
|
Done |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 object cloning, 1 |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
class test { |
||||||
|
public $p1 = 1; |
||||||
|
public $p2 = 2; |
||||||
|
public $p3; |
||||||
|
}; |
||||||
|
|
||||||
|
function main() { |
||||||
|
$obj = new test; |
||||||
|
$obj->p2 = 'A'; |
||||||
|
$obj->p3 = 'B'; |
||||||
|
$copy = clone $obj; |
||||||
|
$copy->p3 = 'C'; |
||||||
|
echo "Object\n"; |
||||||
|
var_dump($obj); |
||||||
|
echo "Clown\n"; |
||||||
|
var_dump($copy); |
||||||
|
echo "Done\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
Object |
||||||
|
object(test)#1 (3) { |
||||||
|
["p1"]=> |
||||||
|
int(1) |
||||||
|
["p2"]=> |
||||||
|
string(1) "A" |
||||||
|
["p3"]=> |
||||||
|
string(1) "B" |
||||||
|
} |
||||||
|
Clown |
||||||
|
object(test)#2 (3) { |
||||||
|
["p1"]=> |
||||||
|
int(1) |
||||||
|
["p2"]=> |
||||||
|
string(1) "A" |
||||||
|
["p3"]=> |
||||||
|
string(1) "C" |
||||||
|
} |
||||||
|
Done |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 object cloning, 2 |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
class test { |
||||||
|
public $p1 = 1; |
||||||
|
public $p2 = 2; |
||||||
|
public $p3; |
||||||
|
public function __clone() { |
||||||
|
} |
||||||
|
}; |
||||||
|
function main() { |
||||||
|
$obj = new test; |
||||||
|
$obj->p2 = 'A'; |
||||||
|
$obj->p3 = 'B'; |
||||||
|
$copy = clone $obj; |
||||||
|
$copy->p3 = 'C'; |
||||||
|
echo "Object\n"; |
||||||
|
var_dump($obj); |
||||||
|
echo "Clown\n"; |
||||||
|
var_dump($copy); |
||||||
|
echo "Done\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
Object |
||||||
|
object(test)#1 (3) { |
||||||
|
["p1"]=> |
||||||
|
int(1) |
||||||
|
["p2"]=> |
||||||
|
string(1) "A" |
||||||
|
["p3"]=> |
||||||
|
string(1) "B" |
||||||
|
} |
||||||
|
Clown |
||||||
|
object(test)#2 (3) { |
||||||
|
["p1"]=> |
||||||
|
int(1) |
||||||
|
["p2"]=> |
||||||
|
string(1) "A" |
||||||
|
["p3"]=> |
||||||
|
string(1) "C" |
||||||
|
} |
||||||
|
Done |
||||||
@ -0,0 +1,57 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 object cloning, 3 |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
class base { |
||||||
|
protected $p1 = 'base:1'; |
||||||
|
public $p2 = 'base:2'; |
||||||
|
public $p3 = 'base:3'; |
||||||
|
public $p4 = 'base:4'; |
||||||
|
public $p5 = 'base:5'; |
||||||
|
private $p6 = 'base:6'; |
||||||
|
public function __clone() { |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class test extends base { |
||||||
|
public $p1 = 'test:1'; |
||||||
|
public $p3 = 'test:3'; |
||||||
|
public $p4 = 'test:4'; |
||||||
|
public $p5 = 'test:5'; |
||||||
|
public function __clone() { |
||||||
|
$this->p5 = 'clone:5'; |
||||||
|
} |
||||||
|
} |
||||||
|
function main() { |
||||||
|
$obj = new test; |
||||||
|
$obj->p4 = 'A'; |
||||||
|
$copy = clone $obj; |
||||||
|
echo "Object\n"; |
||||||
|
print_r($obj); |
||||||
|
echo "Clown\n"; |
||||||
|
print_r($copy); |
||||||
|
echo "Done\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
Object |
||||||
|
test Object |
||||||
|
( |
||||||
|
[p1] => test:1 |
||||||
|
[p2] => base:2 |
||||||
|
[p3] => test:3 |
||||||
|
[p4] => A |
||||||
|
[p5] => test:5 |
||||||
|
[p6:base:private] => base:6 |
||||||
|
) |
||||||
|
Clown |
||||||
|
test Object |
||||||
|
( |
||||||
|
[p1] => test:1 |
||||||
|
[p2] => base:2 |
||||||
|
[p3] => test:3 |
||||||
|
[p4] => A |
||||||
|
[p5] => clone:5 |
||||||
|
[p6:base:private] => base:6 |
||||||
|
) |
||||||
|
Done |
||||||
@ -0,0 +1,83 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 object cloning, 4 |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
abstract class base { |
||||||
|
public $a = 'base'; |
||||||
|
|
||||||
|
// disallow cloning |
||||||
|
private function __clone() {} |
||||||
|
} |
||||||
|
|
||||||
|
class test extends base { |
||||||
|
public $b = 'test'; |
||||||
|
|
||||||
|
// re-enable cloning |
||||||
|
public function __clone() {} |
||||||
|
|
||||||
|
public function show() { |
||||||
|
var_dump($this); |
||||||
|
} |
||||||
|
} |
||||||
|
function main() { |
||||||
|
echo "Original\n"; |
||||||
|
$o1 = new test; |
||||||
|
$o1->a = array(1,2); |
||||||
|
$o1->b = array(3,4); |
||||||
|
$o1->show(); |
||||||
|
|
||||||
|
echo "Clone\n"; |
||||||
|
$o2 = clone $o1; |
||||||
|
$o2->show(); |
||||||
|
|
||||||
|
echo "Modify\n"; |
||||||
|
$o2->a = 5; |
||||||
|
$o2->b = 6; |
||||||
|
$o2->show(); |
||||||
|
|
||||||
|
echo "Done\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
Original |
||||||
|
object(test)#1 (2) { |
||||||
|
["a"]=> |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
[1]=> |
||||||
|
int(2) |
||||||
|
} |
||||||
|
["b"]=> |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
int(3) |
||||||
|
[1]=> |
||||||
|
int(4) |
||||||
|
} |
||||||
|
} |
||||||
|
Clone |
||||||
|
object(test)#2 (2) { |
||||||
|
["a"]=> |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
int(1) |
||||||
|
[1]=> |
||||||
|
int(2) |
||||||
|
} |
||||||
|
["b"]=> |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
int(3) |
||||||
|
[1]=> |
||||||
|
int(4) |
||||||
|
} |
||||||
|
} |
||||||
|
Modify |
||||||
|
object(test)#2 (2) { |
||||||
|
["a"]=> |
||||||
|
int(5) |
||||||
|
["b"]=> |
||||||
|
int(6) |
||||||
|
} |
||||||
|
Done |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 object cloning, 5 |
||||||
|
--SKIPIF-- |
||||||
|
<?php die('skip, failed at compile time'); ?> |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
abstract class base { |
||||||
|
public $a = 'base'; |
||||||
|
|
||||||
|
// disallow cloning once forever |
||||||
|
final protected function __clone() {} |
||||||
|
} |
||||||
|
|
||||||
|
class test extends base { |
||||||
|
// reenabling should fail |
||||||
|
public function __clone() {} |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
|
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECTF-- |
||||||
|
Fatal error: Cannot override final method base::__clone() in %sclone_005.php on line 11 |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 object cloning, 6 |
||||||
|
--INI-- |
||||||
|
error_reporting=2047 |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class MyCloneable { |
||||||
|
static $id = 0; |
||||||
|
|
||||||
|
function __construct() { |
||||||
|
$this->id = self::$id++; |
||||||
|
} |
||||||
|
|
||||||
|
function __clone() { |
||||||
|
$this->address = "New York"; |
||||||
|
$this->id = self::$id++; |
||||||
|
} |
||||||
|
} |
||||||
|
function main() { |
||||||
|
$original = new MyCloneable(); |
||||||
|
|
||||||
|
$original->name = "Hello"; |
||||||
|
$original->address = "Tel-Aviv"; |
||||||
|
|
||||||
|
echo $original->id . "\n"; |
||||||
|
|
||||||
|
$clone = clone $original; |
||||||
|
|
||||||
|
echo $clone->id . "\n"; |
||||||
|
echo $clone->name . "\n"; |
||||||
|
echo $clone->address . "\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECTF-- |
||||||
|
0 |
||||||
|
1 |
||||||
|
Hello |
||||||
|
New York |
||||||
@ -0,0 +1,76 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 A private constructor cannot be called |
||||||
|
--SKIPIF-- |
||||||
|
<?php die('skip'); ?> |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class Test |
||||||
|
{ |
||||||
|
function __construct() |
||||||
|
{ |
||||||
|
echo __METHOD__ . "()\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Derived extends Test |
||||||
|
{ |
||||||
|
function __construct() |
||||||
|
{ |
||||||
|
echo __METHOD__ . "()\n"; |
||||||
|
parent::__construct(); |
||||||
|
} |
||||||
|
|
||||||
|
static function f() |
||||||
|
{ |
||||||
|
new Derived; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
class TestPriv |
||||||
|
{ |
||||||
|
private function __construct() |
||||||
|
{ |
||||||
|
echo __METHOD__ . "()\n"; |
||||||
|
} |
||||||
|
|
||||||
|
static function f() |
||||||
|
{ |
||||||
|
new TestPriv; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
class DerivedPriv extends TestPriv |
||||||
|
{ |
||||||
|
function __construct() |
||||||
|
{ |
||||||
|
echo __METHOD__ . "()\n"; |
||||||
|
parent::__construct(); |
||||||
|
} |
||||||
|
|
||||||
|
static function f() |
||||||
|
{ |
||||||
|
new DerivedPriv; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
Derived::f(); |
||||||
|
TestPriv::f(); |
||||||
|
DerivedPriv::f(); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECTF-- |
||||||
|
Derived::__construct() |
||||||
|
Test::__construct() |
||||||
|
TestPriv::__construct() |
||||||
|
DerivedPriv::__construct() |
||||||
|
|
||||||
|
Fatal error: Uncaught Error: Cannot call private TestPriv::__construct() in %sctor_visibility.php:%d |
||||||
|
Stack trace: |
||||||
|
#0 %s(%d): DerivedPriv->__construct() |
||||||
|
#1 %s(%d): DerivedPriv::f() |
||||||
|
#2 {main} |
||||||
|
thrown in %sctor_visibility.php on line %d |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 dereferencing of objects from methods |
||||||
|
--SKIPIF-- |
||||||
|
<?php die('skip'); ?> |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class Name { |
||||||
|
function __construct(public string $name) {} |
||||||
|
|
||||||
|
function display() { |
||||||
|
echo $this->name . "\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Person { |
||||||
|
private $name; |
||||||
|
|
||||||
|
function __construct($_name, $_address) { |
||||||
|
$this->name = new Name($_name); |
||||||
|
} |
||||||
|
|
||||||
|
function getName() { |
||||||
|
return $this->name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
$person = new Person("John", "New York"); |
||||||
|
$person->getName()->display(); |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
John |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
--TEST-- |
||||||
|
ZE2 Destructors and echo |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class Test |
||||||
|
{ |
||||||
|
function __construct() { |
||||||
|
echo __METHOD__ . "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
function __destruct() { |
||||||
|
echo __METHOD__ . "\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
$o = new Test; |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
Test::__construct |
||||||
|
Test::__destruct |
||||||
Loading…
Reference in new issue