summaryrefslogtreecommitdiff
path: root/tests/classes
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2013-03-14 05:42:27 +0000
committer <>2013-04-03 16:25:08 +0000
commitc4dd7a1a684490673e25aaf4fabec5df138854c4 (patch)
tree4d57c44caae4480efff02b90b9be86f44bf25409 /tests/classes
downloadphp2-master.tar.gz
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'tests/classes')
-rw-r--r--tests/classes/__call_001.phpt42
-rw-r--r--tests/classes/__call_002.phpt15
-rw-r--r--tests/classes/__call_003.phpt33
-rw-r--r--tests/classes/__call_004.phpt41
-rw-r--r--tests/classes/__call_005.phpt37
-rw-r--r--tests/classes/__call_006.phpt77
-rw-r--r--tests/classes/__call_007.phpt74
-rw-r--r--tests/classes/__set__get_001.phpt72
-rw-r--r--tests/classes/__set__get_002.phpt14
-rw-r--r--tests/classes/__set__get_003.phpt14
-rw-r--r--tests/classes/__set__get_004.phpt39
-rw-r--r--tests/classes/__set__get_005.phpt68
-rw-r--r--tests/classes/__set_data_corrupt.phpt29
-rw-r--r--tests/classes/abstract.phpt30
-rw-r--r--tests/classes/abstract_by_interface_001.phpt33
-rw-r--r--tests/classes/abstract_by_interface_002.phpt33
-rw-r--r--tests/classes/abstract_class.phpt29
-rw-r--r--tests/classes/abstract_derived.phpt20
-rw-r--r--tests/classes/abstract_final.phpt16
-rw-r--r--tests/classes/abstract_inherit.phpt22
-rw-r--r--tests/classes/abstract_not_declared.phpt15
-rw-r--r--tests/classes/abstract_redeclare.phpt22
-rw-r--r--tests/classes/abstract_static.phpt36
-rw-r--r--tests/classes/abstract_user_call.phpt30
-rw-r--r--tests/classes/array_access_001.phpt198
-rw-r--r--tests/classes/array_access_002.phpt198
-rw-r--r--tests/classes/array_access_003.phpt59
-rw-r--r--tests/classes/array_access_004.phpt57
-rw-r--r--tests/classes/array_access_005.phpt77
-rw-r--r--tests/classes/array_access_006.phpt37
-rw-r--r--tests/classes/array_access_007.phpt57
-rw-r--r--tests/classes/array_access_008.phpt67
-rw-r--r--tests/classes/array_access_009.phpt190
-rw-r--r--tests/classes/array_access_010.phpt168
-rw-r--r--tests/classes/array_access_011.phpt187
-rw-r--r--tests/classes/array_access_012.phpt36
-rw-r--r--tests/classes/array_access_013.phpt58
-rw-r--r--tests/classes/arrayobject_001.phpt13
-rw-r--r--tests/classes/assign_op_property_001.phpt31
-rw-r--r--tests/classes/autoload_001.phpt24
-rw-r--r--tests/classes/autoload_002.phpt27
-rw-r--r--tests/classes/autoload_003.phpt25
-rw-r--r--tests/classes/autoload_004.phpt28
-rw-r--r--tests/classes/autoload_005.phpt45
-rw-r--r--tests/classes/autoload_006.phpt40
-rw-r--r--tests/classes/autoload_007.phpt15
-rw-r--r--tests/classes/autoload_008.phpt26
-rw-r--r--tests/classes/autoload_009.phpt20
-rw-r--r--tests/classes/autoload_010.phpt18
-rw-r--r--tests/classes/autoload_011.phpt18
-rw-r--r--tests/classes/autoload_012.phpt15
-rw-r--r--tests/classes/autoload_013.phpt22
-rw-r--r--tests/classes/autoload_014.phpt22
-rw-r--r--tests/classes/autoload_015.phpt22
-rw-r--r--tests/classes/autoload_016.phpt23
-rw-r--r--tests/classes/autoload_017.phpt23
-rw-r--r--tests/classes/autoload_018.phpt48
-rw-r--r--tests/classes/autoload_019.phpt14
-rw-r--r--tests/classes/autoload_020.phpt17
-rwxr-xr-xtests/classes/autoload_derived.p5c6
-rwxr-xr-xtests/classes/autoload_implements.p5c10
-rwxr-xr-xtests/classes/autoload_interface.p5c7
-rwxr-xr-xtests/classes/autoload_root.p5c10
-rw-r--r--tests/classes/bug23951.phpt44
-rw-r--r--tests/classes/bug24399.phpt12
-rw-r--r--tests/classes/bug24445.phpt12
-rw-r--r--tests/classes/bug26737.phpt22
-rw-r--r--tests/classes/bug27468.phpt17
-rw-r--r--tests/classes/bug27504.phpt25
-rw-r--r--tests/classes/bug29446.phpt19
-rw-r--r--tests/classes/bug63462.phpt71
-rw-r--r--tests/classes/class_abstract.phpt28
-rw-r--r--tests/classes/class_example.phpt85
-rw-r--r--tests/classes/class_final.phpt22
-rw-r--r--tests/classes/class_stdclass.phpt14
-rw-r--r--tests/classes/clone_001.phpt43
-rw-r--r--tests/classes/clone_002.phpt45
-rw-r--r--tests/classes/clone_003.phpt58
-rw-r--r--tests/classes/clone_004.phpt82
-rw-r--r--tests/classes/clone_005.phpt19
-rw-r--r--tests/classes/clone_006.phpt41
-rw-r--r--tests/classes/constants_basic_001.phpt89
-rw-r--r--tests/classes/constants_basic_002.phpt32
-rw-r--r--tests/classes/constants_basic_003.inc5
-rw-r--r--tests/classes/constants_basic_003.phpt28
-rw-r--r--tests/classes/constants_basic_004.phpt99
-rw-r--r--tests/classes/constants_basic_005.phpt16
-rw-r--r--tests/classes/constants_basic_006.phpt43
-rw-r--r--tests/classes/constants_error_001.phpt13
-rw-r--r--tests/classes/constants_error_002.phpt12
-rw-r--r--tests/classes/constants_error_003.phpt20
-rw-r--r--tests/classes/constants_error_004.phpt13
-rw-r--r--tests/classes/constants_error_005.phpt12
-rw-r--r--tests/classes/constants_error_006.phpt16
-rw-r--r--tests/classes/constants_error_007.phpt15
-rw-r--r--tests/classes/constants_scope_001.phpt38
-rw-r--r--tests/classes/ctor_dtor.phpt40
-rw-r--r--tests/classes/ctor_dtor_inheritance.phpt99
-rw-r--r--tests/classes/ctor_failure.phpt33
-rw-r--r--tests/classes/ctor_in_interface_01.phpt19
-rw-r--r--tests/classes/ctor_in_interface_02.phpt34
-rw-r--r--tests/classes/ctor_in_interface_03.phpt23
-rw-r--r--tests/classes/ctor_in_interface_04.phpt26
-rw-r--r--tests/classes/ctor_name_clash.phpt22
-rw-r--r--tests/classes/ctor_visibility.phpt69
-rw-r--r--tests/classes/dereferencing_001.phpt35
-rw-r--r--tests/classes/destructor_and_echo.phpt24
-rw-r--r--tests/classes/destructor_and_exceptions.phpt60
-rw-r--r--tests/classes/destructor_and_globals.phpt56
-rw-r--r--tests/classes/destructor_and_references.phpt26
-rw-r--r--tests/classes/destructor_inheritance.phpt29
-rw-r--r--tests/classes/destructor_visibility_001.phpt24
-rw-r--r--tests/classes/destructor_visibility_002.phpt24
-rw-r--r--tests/classes/destructor_visibility_003.phpt28
-rw-r--r--tests/classes/factory_001.phpt35
-rw-r--r--tests/classes/factory_and_singleton_001.phpt101
-rw-r--r--tests/classes/factory_and_singleton_002.phpt100
-rw-r--r--tests/classes/factory_and_singleton_003.phpt18
-rw-r--r--tests/classes/factory_and_singleton_004.phpt18
-rw-r--r--tests/classes/factory_and_singleton_005.phpt19
-rw-r--r--tests/classes/factory_and_singleton_006.phpt20
-rw-r--r--tests/classes/factory_and_singleton_007.phpt20
-rw-r--r--tests/classes/factory_and_singleton_008.phpt20
-rw-r--r--tests/classes/factory_and_singleton_009.phpt21
-rw-r--r--tests/classes/factory_and_singleton_010.phpt21
-rw-r--r--tests/classes/final.phpt31
-rw-r--r--tests/classes/final_abstract.phpt16
-rw-r--r--tests/classes/final_ctor1.phpt29
-rw-r--r--tests/classes/final_ctor2.phpt29
-rw-r--r--tests/classes/final_ctor3.phpt13
-rw-r--r--tests/classes/final_redeclare.phpt25
-rw-r--r--tests/classes/implicit_instantiation_001.phpt146
-rw-r--r--tests/classes/incdec_property_001.phpt31
-rw-r--r--tests/classes/incdec_property_002.phpt31
-rw-r--r--tests/classes/incdec_property_003.phpt31
-rw-r--r--tests/classes/incdec_property_004.phpt31
-rw-r--r--tests/classes/inheritance.phpt56
-rw-r--r--tests/classes/inheritance_002.phpt71
-rw-r--r--tests/classes/inheritance_003.phpt21
-rw-r--r--tests/classes/inheritance_004.phpt21
-rw-r--r--tests/classes/inheritance_005.phpt57
-rw-r--r--tests/classes/inheritance_006.phpt24
-rw-r--r--tests/classes/inheritance_007.phpt39
-rw-r--r--tests/classes/interface_and_extends.phpt26
-rw-r--r--tests/classes/interface_class.phpt14
-rw-r--r--tests/classes/interface_constant_inheritance_001.phpt17
-rw-r--r--tests/classes/interface_constant_inheritance_002.phpt17
-rw-r--r--tests/classes/interface_constant_inheritance_003.phpt20
-rw-r--r--tests/classes/interface_constant_inheritance_004.phpt18
-rw-r--r--tests/classes/interface_doubled.phpt201
-rw-r--r--tests/classes/interface_implemented.phpt103
-rw-r--r--tests/classes/interface_instantiate.phpt16
-rw-r--r--tests/classes/interface_member.phpt13
-rw-r--r--tests/classes/interface_method.phpt15
-rw-r--r--tests/classes/interface_method_final.phpt15
-rw-r--r--tests/classes/interface_method_private.phpt15
-rw-r--r--tests/classes/interface_must_be_implemented.phpt17
-rw-r--r--tests/classes/interface_optional_arg.phpt27
-rw-r--r--tests/classes/interface_optional_arg_002.phpt24
-rw-r--r--tests/classes/interface_optional_arg_003.inc4
-rw-r--r--tests/classes/interface_optional_arg_003.phpt17
-rw-r--r--tests/classes/interfaces_001.phpt26
-rw-r--r--tests/classes/interfaces_002.phpt29
-rw-r--r--tests/classes/interfaces_003.phpt26
-rw-r--r--tests/classes/iterators_001.phpt200
-rw-r--r--tests/classes/iterators_002.phpt113
-rw-r--r--tests/classes/iterators_003.phpt115
-rw-r--r--tests/classes/iterators_004.phpt61
-rw-r--r--tests/classes/iterators_005.phpt19
-rw-r--r--tests/classes/iterators_006.phpt87
-rw-r--r--tests/classes/iterators_007.phpt43
-rw-r--r--tests/classes/iterators_008.phpt45
-rw-r--r--tests/classes/method_call_variation_001.phpt37
-rw-r--r--tests/classes/method_override_optional_arg_001.phpt33
-rw-r--r--tests/classes/method_override_optional_arg_002.phpt22
-rw-r--r--tests/classes/new_001.phpt48
-rw-r--r--tests/classes/object_reference_001.phpt27
-rw-r--r--tests/classes/private_001.phpt26
-rw-r--r--tests/classes/private_002.phpt35
-rw-r--r--tests/classes/private_003.phpt36
-rw-r--r--tests/classes/private_003b.phpt37
-rw-r--r--tests/classes/private_004.phpt32
-rw-r--r--tests/classes/private_004b.phpt35
-rw-r--r--tests/classes/private_005.phpt32
-rw-r--r--tests/classes/private_005b.phpt35
-rw-r--r--tests/classes/private_006.phpt41
-rw-r--r--tests/classes/private_006b.phpt41
-rw-r--r--tests/classes/private_007.phpt30
-rw-r--r--tests/classes/private_007b.phpt31
-rw-r--r--tests/classes/private_members.phpt103
-rw-r--r--tests/classes/private_redeclare.phpt38
-rw-r--r--tests/classes/property_override_privateStatic_private.phpt33
-rw-r--r--tests/classes/property_override_privateStatic_privateStatic.phpt32
-rw-r--r--tests/classes/property_override_privateStatic_protected.phpt33
-rw-r--r--tests/classes/property_override_privateStatic_protectedStatic.phpt32
-rw-r--r--tests/classes/property_override_privateStatic_public.phpt33
-rw-r--r--tests/classes/property_override_privateStatic_publicStatic.phpt32
-rw-r--r--tests/classes/property_override_private_private.phpt34
-rw-r--r--tests/classes/property_override_private_privateStatic.phpt34
-rw-r--r--tests/classes/property_override_private_protected.phpt34
-rw-r--r--tests/classes/property_override_private_protectedStatic.phpt34
-rw-r--r--tests/classes/property_override_private_public.phpt34
-rw-r--r--tests/classes/property_override_private_publicStatic.phpt34
-rw-r--r--tests/classes/property_override_protectedStatic_private.phpt33
-rw-r--r--tests/classes/property_override_protectedStatic_privateStatic.phpt32
-rw-r--r--tests/classes/property_override_protectedStatic_protected.phpt33
-rw-r--r--tests/classes/property_override_protectedStatic_protectedStatic.phpt32
-rw-r--r--tests/classes/property_override_protectedStatic_public.phpt33
-rw-r--r--tests/classes/property_override_protectedStatic_publicStatic.phpt33
-rw-r--r--tests/classes/property_override_protected_private.phpt33
-rw-r--r--tests/classes/property_override_protected_privateStatic.phpt33
-rw-r--r--tests/classes/property_override_protected_protected.phpt34
-rw-r--r--tests/classes/property_override_protected_protectedStatic.phpt33
-rw-r--r--tests/classes/property_override_protected_public.phpt34
-rw-r--r--tests/classes/property_override_protected_publicStatic.phpt33
-rw-r--r--tests/classes/property_override_publicStatic_private.phpt33
-rw-r--r--tests/classes/property_override_publicStatic_privateStatic.phpt32
-rw-r--r--tests/classes/property_override_publicStatic_protected.phpt33
-rw-r--r--tests/classes/property_override_publicStatic_protectedStatic.phpt32
-rw-r--r--tests/classes/property_override_publicStatic_public.phpt33
-rw-r--r--tests/classes/property_override_publicStatic_publicStatic.phpt32
-rw-r--r--tests/classes/property_override_public_private.phpt34
-rw-r--r--tests/classes/property_override_public_privateStatic.phpt33
-rw-r--r--tests/classes/property_override_public_protected.phpt34
-rw-r--r--tests/classes/property_override_public_protectedStatic.phpt33
-rw-r--r--tests/classes/property_override_public_public.phpt34
-rw-r--r--tests/classes/property_override_public_publicStatic.phpt33
-rw-r--r--tests/classes/property_recreate_private.phpt81
-rw-r--r--tests/classes/property_recreate_protected.phpt53
-rw-r--r--tests/classes/protected_001.phpt26
-rw-r--r--tests/classes/protected_001b.phpt27
-rw-r--r--tests/classes/protected_002.phpt35
-rw-r--r--tests/classes/serialize_001.phpt79
-rw-r--r--tests/classes/singleton_001.phpt37
-rw-r--r--tests/classes/static_mix_1.phpt26
-rw-r--r--tests/classes/static_mix_2.phpt27
-rw-r--r--tests/classes/static_properties_001.phpt27
-rw-r--r--tests/classes/static_properties_003.phpt49
-rw-r--r--tests/classes/static_properties_003_error1.phpt18
-rw-r--r--tests/classes/static_properties_003_error2.phpt18
-rw-r--r--tests/classes/static_properties_003_error3.phpt18
-rw-r--r--tests/classes/static_properties_003_error4.phpt18
-rw-r--r--tests/classes/static_properties_004.phpt37
-rw-r--r--tests/classes/static_properties_undeclared_assign.phpt9
-rw-r--r--tests/classes/static_properties_undeclared_assignInc.phpt9
-rw-r--r--tests/classes/static_properties_undeclared_assignRef.phpt10
-rw-r--r--tests/classes/static_properties_undeclared_inc.phpt9
-rw-r--r--tests/classes/static_properties_undeclared_isset.phpt9
-rw-r--r--tests/classes/static_properties_undeclared_read.phpt9
-rw-r--r--tests/classes/static_this.phpt39
-rw-r--r--tests/classes/this.phpt54
-rw-r--r--tests/classes/tostring_001.phpt130
-rw-r--r--tests/classes/tostring_002.phpt31
-rw-r--r--tests/classes/tostring_003.phpt33
-rw-r--r--tests/classes/tostring_004.phpt56
-rw-r--r--tests/classes/type_hinting_001.phpt38
-rw-r--r--tests/classes/type_hinting_002.phpt16
-rw-r--r--tests/classes/type_hinting_003.phpt60
-rw-r--r--tests/classes/type_hinting_004.phpt109
-rw-r--r--tests/classes/type_hinting_005a.phpt18
-rw-r--r--tests/classes/type_hinting_005b.phpt14
-rw-r--r--tests/classes/type_hinting_005c.phpt14
-rw-r--r--tests/classes/type_hinting_005d.phpt14
-rw-r--r--tests/classes/unset_properties.phpt154
-rw-r--r--tests/classes/visibility_000a.phpt33
-rw-r--r--tests/classes/visibility_000b.phpt33
-rw-r--r--tests/classes/visibility_000c.phpt33
-rw-r--r--tests/classes/visibility_001a.phpt33
-rw-r--r--tests/classes/visibility_001b.phpt33
-rw-r--r--tests/classes/visibility_001c.phpt33
-rw-r--r--tests/classes/visibility_002a.phpt33
-rw-r--r--tests/classes/visibility_002b.phpt33
-rw-r--r--tests/classes/visibility_002c.phpt33
-rw-r--r--tests/classes/visibility_003a.phpt33
-rw-r--r--tests/classes/visibility_003b.phpt33
-rw-r--r--tests/classes/visibility_003c.phpt33
-rw-r--r--tests/classes/visibility_004a.phpt33
-rw-r--r--tests/classes/visibility_004b.phpt33
-rw-r--r--tests/classes/visibility_004c.phpt33
-rw-r--r--tests/classes/visibility_005.phpt59
280 files changed, 10893 insertions, 0 deletions
diff --git a/tests/classes/__call_001.phpt b/tests/classes/__call_001.phpt
new file mode 100644
index 0000000..f9708e0
--- /dev/null
+++ b/tests/classes/__call_001.phpt
@@ -0,0 +1,42 @@
+--TEST--
+ZE2 __call()
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Caller {
+ public $x = array(1, 2, 3);
+
+ function __call($m, $a) {
+ echo "Method $m called:\n";
+ var_dump($a);
+ return $this->x;
+ }
+}
+
+$foo = new Caller();
+$a = $foo->test(1, '2', 3.4, true);
+var_dump($a);
+
+?>
+--EXPECT--
+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)
+}
diff --git a/tests/classes/__call_002.phpt b/tests/classes/__call_002.phpt
new file mode 100644
index 0000000..53a179f
--- /dev/null
+++ b/tests/classes/__call_002.phpt
@@ -0,0 +1,15 @@
+--TEST--
+ZE2 __call() signature check
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Test {
+ function __call() {
+ }
+}
+
+?>
+--EXPECTF--
+Fatal error: Method Test::__call() must take exactly 2 arguments in %s__call_002.php on line %d
diff --git a/tests/classes/__call_003.phpt b/tests/classes/__call_003.phpt
new file mode 100644
index 0000000..c7aa95c
--- /dev/null
+++ b/tests/classes/__call_003.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Force pass-by-reference to __call
+--FILE--
+<?php
+ class C
+ {
+ function __call($name, $values)
+ {
+ $values[0][0] = 'changed';
+ }
+ }
+
+ $a = array('original');
+
+ $b = array('original');
+ $hack =& $b[0];
+
+ $c = new C;
+ $c->f($a);
+ $c->f($b);
+
+ var_dump($a, $b);
+?>
+--EXPECTF--
+array(1) {
+ [0]=>
+ string(8) "original"
+}
+array(1) {
+ [0]=>
+ &string(7) "changed"
+}
+
diff --git a/tests/classes/__call_004.phpt b/tests/classes/__call_004.phpt
new file mode 100644
index 0000000..2072112
--- /dev/null
+++ b/tests/classes/__call_004.phpt
@@ -0,0 +1,41 @@
+--TEST--
+When __call() is invoked via ::, ensure current scope's __call() is favoured over the specified class's __call().
+--FILE--
+<?php
+class A {
+ function __call($strMethod, $arrArgs) {
+ echo "In " . __METHOD__ . "($strMethod, array(" . implode(',',$arrArgs) . "))\n";
+ var_dump($this);
+ }
+}
+
+class B extends A {
+ function __call($strMethod, $arrArgs) {
+ echo "In " . __METHOD__ . "($strMethod, array(" . implode(',',$arrArgs) . "))\n";
+ var_dump($this);
+ }
+
+ function test() {
+ A::test1(1,'a');
+ B::test2(1,'a');
+ self::test3(1,'a');
+ parent::test4(1,'a');
+ }
+}
+
+$b = new B();
+$b->test();
+?>
+--EXPECTF--
+In B::__call(test1, array(1,a))
+object(B)#1 (0) {
+}
+In B::__call(test2, array(1,a))
+object(B)#1 (0) {
+}
+In B::__call(test3, array(1,a))
+object(B)#1 (0) {
+}
+In B::__call(test4, array(1,a))
+object(B)#1 (0) {
+} \ No newline at end of file
diff --git a/tests/classes/__call_005.phpt b/tests/classes/__call_005.phpt
new file mode 100644
index 0000000..6e15848
--- /dev/null
+++ b/tests/classes/__call_005.phpt
@@ -0,0 +1,37 @@
+--TEST--
+When __call() is invoked via ::, ensure private implementation of __call() in superclass is accessed without error.
+--FILE--
+<?php
+class A {
+ private function __call($strMethod, $arrArgs) {
+ echo "In " . __METHOD__ . "($strMethod, array(" . implode(',',$arrArgs) . "))\n";
+ var_dump($this);
+ }
+}
+
+class B extends A {
+ function test() {
+ A::test1(1,'a');
+ B::test2(1,'a');
+ self::test3(1,'a');
+ parent::test4(1,'a');
+ }
+}
+
+$b = new B();
+$b->test();
+?>
+--EXPECTF--
+Warning: The magic method __call() must have public visibility and cannot be static in %s__call_005.php on line 3
+In A::__call(test1, array(1,a))
+object(B)#1 (0) {
+}
+In A::__call(test2, array(1,a))
+object(B)#1 (0) {
+}
+In A::__call(test3, array(1,a))
+object(B)#1 (0) {
+}
+In A::__call(test4, array(1,a))
+object(B)#1 (0) {
+}
diff --git a/tests/classes/__call_006.phpt b/tests/classes/__call_006.phpt
new file mode 100644
index 0000000..a65fafb
--- /dev/null
+++ b/tests/classes/__call_006.phpt
@@ -0,0 +1,77 @@
+--TEST--
+Ensure exceptions are handled properly when thrown in __call.
+--FILE--
+<?php
+class A {
+ function __call($strMethod, $arrArgs) {
+ var_dump($this);
+ throw new Exception;
+ echo "You should not see this";
+ }
+ function test() {
+ A::unknownCalledWithSRO(1,2,3);
+ }
+}
+
+class B extends A {
+ function test() {
+ B::unknownCalledWithSROFromChild(1,2,3);
+ }
+}
+
+$a = new A();
+
+echo "---> Invoke __call via simple method call.\n";
+try {
+ $a->unknown();
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+
+echo "\n\n---> Invoke __call via scope resolution operator within instance.\n";
+try {
+ $a->test();
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+
+echo "\n\n---> Invoke __call via scope resolution operator within child instance.\n";
+$b = new B();
+try {
+ $b->test();
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+
+echo "\n\n---> Invoke __call via callback.\n";
+try {
+ call_user_func(array($b, 'unknownCallback'), 1,2,3);
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+?>
+==DONE==
+--EXPECTF--
+---> Invoke __call via simple method call.
+object(A)#%d (0) {
+}
+Exception caught OK; continuing.
+
+
+---> Invoke __call via scope resolution operator within instance.
+object(A)#%d (0) {
+}
+Exception caught OK; continuing.
+
+
+---> Invoke __call via scope resolution operator within child instance.
+object(B)#%d (0) {
+}
+Exception caught OK; continuing.
+
+
+---> Invoke __call via callback.
+object(B)#%d (0) {
+}
+Exception caught OK; continuing.
+==DONE== \ No newline at end of file
diff --git a/tests/classes/__call_007.phpt b/tests/classes/__call_007.phpt
new file mode 100644
index 0000000..d79dba3
--- /dev/null
+++ b/tests/classes/__call_007.phpt
@@ -0,0 +1,74 @@
+--TEST--
+Ensure exceptions are handled properly when thrown in a statically declared __call.
+--FILE--
+<?php
+class A {
+ static function __call($strMethod, $arrArgs) {
+ @var_dump($this);
+ throw new Exception;
+ echo "You should not see this";
+ }
+ function test() {
+ A::unknownCalledWithSRO(1,2,3);
+ }
+}
+
+class B extends A {
+ function test() {
+ B::unknownCalledWithSROFromChild(1,2,3);
+ }
+}
+
+$a = new A();
+
+echo "---> Invoke __call via simple method call.\n";
+try {
+ $a->unknown();
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+
+echo "\n\n---> Invoke __call via scope resolution operator within instance.\n";
+try {
+ $a->test();
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+
+echo "\n\n---> Invoke __call via scope resolution operator within child instance.\n";
+$b = new B();
+try {
+ $b->test();
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+
+echo "\n\n---> Invoke __call via callback.\n";
+try {
+ call_user_func(array($b, 'unknownCallback'), 1,2,3);
+} catch (Exception $e) {
+ echo "Exception caught OK; continuing.\n";
+}
+?>
+==DONE==
+--EXPECTF--
+Warning: The magic method __call() must have public visibility and cannot be static in %s on line 3
+---> Invoke __call via simple method call.
+NULL
+Exception caught OK; continuing.
+
+
+---> Invoke __call via scope resolution operator within instance.
+NULL
+Exception caught OK; continuing.
+
+
+---> Invoke __call via scope resolution operator within child instance.
+NULL
+Exception caught OK; continuing.
+
+
+---> Invoke __call via callback.
+NULL
+Exception caught OK; continuing.
+==DONE== \ No newline at end of file
diff --git a/tests/classes/__set__get_001.phpt b/tests/classes/__set__get_001.phpt
new file mode 100644
index 0000000..beb688c
--- /dev/null
+++ b/tests/classes/__set__get_001.phpt
@@ -0,0 +1,72 @@
+--TEST--
+ZE2 __set() and __get()
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class setter {
+ public $n;
+ public $x = array('a' => 1, 'b' => 2, 'c' => 3);
+
+ function __get($nm) {
+ echo "Getting [$nm]\n";
+
+ if (isset($this->x[$nm])) {
+ $r = $this->x[$nm];
+ echo "Returning: $r\n";
+ return $r;
+ }
+ else {
+ echo "Nothing!\n";
+ }
+ }
+
+ 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";
+ }
+ }
+}
+
+$foo = new Setter();
+
+// this doesn't go through __set()... should it?
+$foo->n = 1;
+
+// the rest are fine...
+$foo->a = 100;
+$foo->a++;
+$foo->z++;
+var_dump($foo);
+
+?>
+--EXPECTF--
+Setting [a] to 100
+OK!
+Getting [a]
+Returning: 100
+Setting [a] to 101
+OK!
+Getting [z]
+Nothing!
+Setting [z] to 1
+Not OK!
+object(setter)#%d (2) {
+ ["n"]=>
+ int(1)
+ ["x"]=>
+ array(3) {
+ ["a"]=>
+ int(101)
+ ["b"]=>
+ int(2)
+ ["c"]=>
+ int(3)
+ }
+}
diff --git a/tests/classes/__set__get_002.phpt b/tests/classes/__set__get_002.phpt
new file mode 100644
index 0000000..71111cc
--- /dev/null
+++ b/tests/classes/__set__get_002.phpt
@@ -0,0 +1,14 @@
+--TEST--
+ZE2 __get() signature check
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class Test {
+ function __get($x,$y) {
+ }
+}
+
+?>
+--EXPECTF--
+Fatal error: Method Test::__get() must take exactly 1 argument in %s__set__get_002.php on line %d
diff --git a/tests/classes/__set__get_003.phpt b/tests/classes/__set__get_003.phpt
new file mode 100644
index 0000000..390d303
--- /dev/null
+++ b/tests/classes/__set__get_003.phpt
@@ -0,0 +1,14 @@
+--TEST--
+ZE2 __set() signature check
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class Test {
+ function __set() {
+ }
+}
+
+?>
+--EXPECTF--
+Fatal error: Method Test::__set() must take exactly 2 arguments in %s__set__get_003.php on line %d
diff --git a/tests/classes/__set__get_004.phpt b/tests/classes/__set__get_004.phpt
new file mode 100644
index 0000000..e3061da
--- /dev/null
+++ b/tests/classes/__set__get_004.phpt
@@ -0,0 +1,39 @@
+--TEST--
+ZE2 __set() and __get()
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class Test {
+ protected $x;
+
+ function __get($name) {
+ if (isset($this->x[$name])) {
+ return $this->x[$name];
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+ function __set($name, $val) {
+ $this->x[$name] = $val;
+ }
+}
+
+$foo = new Test();
+$bar = new Test();
+$bar->baz = "Check";
+
+$foo->bar = $bar;
+
+var_dump($bar->baz);
+var_dump($foo->bar->baz);
+
+?>
+===DONE===
+--EXPECTF--
+string(5) "Check"
+string(5) "Check"
+===DONE===
diff --git a/tests/classes/__set__get_005.phpt b/tests/classes/__set__get_005.phpt
new file mode 100644
index 0000000..d8bbad3
--- /dev/null
+++ b/tests/classes/__set__get_005.phpt
@@ -0,0 +1,68 @@
+--TEST--
+ZE2 __set() and __get()
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class Test
+{
+ protected $x;
+
+ function __get($name) {
+ echo __METHOD__ . "\n";
+ if (isset($this->x[$name])) {
+ return $this->x[$name];
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+ function __set($name, $val) {
+ echo __METHOD__ . "\n";
+ $this->x[$name] = $val;
+ }
+}
+
+class AutoGen
+{
+ protected $x;
+
+ function __get($name) {
+ echo __METHOD__ . "\n";
+ if (!isset($this->x[$name])) {
+ $this->x[$name] = new Test();
+ }
+ return $this->x[$name];
+ }
+
+ function __set($name, $val) {
+ echo __METHOD__ . "\n";
+ $this->x[$name] = $val;
+ }
+}
+
+$foo = new AutoGen();
+$foo->bar->baz = "Check";
+
+var_dump($foo->bar);
+var_dump($foo->bar->baz);
+
+?>
+===DONE===
+--EXPECTF--
+AutoGen::__get
+Test::__set
+AutoGen::__get
+object(Test)#%d (1) {
+ ["x":protected]=>
+ array(1) {
+ ["baz"]=>
+ string(5) "Check"
+ }
+}
+AutoGen::__get
+Test::__get
+string(5) "Check"
+===DONE===
diff --git a/tests/classes/__set_data_corrupt.phpt b/tests/classes/__set_data_corrupt.phpt
new file mode 100644
index 0000000..6a52bd4
--- /dev/null
+++ b/tests/classes/__set_data_corrupt.phpt
@@ -0,0 +1,29 @@
+--TEST--
+ZE2 Data corruption in __set
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 is needed'); ?>
+--FILE--
+<?php
+$f = 'c="foo"';
+class foo {
+ const foobar=1;
+ public $pp = array('t'=>null);
+
+ function bar() {
+ echo $this->t ='f';
+ }
+ function __get($prop)
+ {
+ return $this->pp[$prop];
+ }
+ function __set($prop, $val)
+ {
+ echo "__set";
+ $this->pp[$prop] = '';
+ }
+}
+$f = new foo;
+$f->bar();
+?>
+--EXPECT--
+__setf
diff --git a/tests/classes/abstract.phpt b/tests/classes/abstract.phpt
new file mode 100644
index 0000000..fbebf4d
--- /dev/null
+++ b/tests/classes/abstract.phpt
@@ -0,0 +1,30 @@
+--TEST--
+ZE2 An abstract method may not be called
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+abstract class fail {
+ abstract function show();
+}
+
+class pass extends fail {
+ function show() {
+ echo "Call to function show()\n";
+ }
+ function error() {
+ parent::show();
+ }
+}
+
+$t = new pass();
+$t->show();
+$t->error();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call to function show()
+
+Fatal error: Cannot call abstract method fail::show() in %s on line %d
diff --git a/tests/classes/abstract_by_interface_001.phpt b/tests/classes/abstract_by_interface_001.phpt
new file mode 100644
index 0000000..7565fdf
--- /dev/null
+++ b/tests/classes/abstract_by_interface_001.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 An abstract method may not be called
+--FILE--
+<?php
+
+class Root {
+}
+
+interface MyInterface
+{
+ function MyInterfaceFunc();
+}
+
+abstract class Derived extends Root implements MyInterface {
+}
+
+class Leaf extends Derived
+{
+ function MyInterfaceFunc() {}
+}
+
+var_dump(new Leaf);
+
+class Fails extends Root implements MyInterface {
+}
+
+?>
+===DONE===
+--EXPECTF--
+object(Leaf)#%d (0) {
+}
+
+Fatal error: Class Fails contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (MyInterface::MyInterfaceFunc) in %sabstract_by_interface_001.php on line %d
diff --git a/tests/classes/abstract_by_interface_002.phpt b/tests/classes/abstract_by_interface_002.phpt
new file mode 100644
index 0000000..77c5619
--- /dev/null
+++ b/tests/classes/abstract_by_interface_002.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 An abstract method may not be called
+--FILE--
+<?php
+
+class Root {
+}
+
+interface MyInterface
+{
+ static function MyInterfaceFunc();
+}
+
+abstract class Derived extends Root implements MyInterface {
+}
+
+class Leaf extends Derived
+{
+ static function MyInterfaceFunc() {}
+}
+
+var_dump(new Leaf);
+
+class Fails extends Root implements MyInterface {
+}
+
+?>
+===DONE===
+--EXPECTF--
+object(Leaf)#%d (0) {
+}
+
+Fatal error: Class Fails contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (MyInterface::MyInterfaceFunc) in %sabstract_by_interface_002.php on line %d
diff --git a/tests/classes/abstract_class.phpt b/tests/classes/abstract_class.phpt
new file mode 100644
index 0000000..571a9b9
--- /dev/null
+++ b/tests/classes/abstract_class.phpt
@@ -0,0 +1,29 @@
+--TEST--
+ZE2 An abstract class cannot be instantiated
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+abstract class fail {
+ abstract function show();
+}
+
+class pass extends fail {
+ function show() {
+ echo "Call to function show()\n";
+ }
+}
+
+$t2 = new pass();
+$t2->show();
+
+$t = new fail();
+$t->show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call to function show()
+
+Fatal error: Cannot instantiate abstract class fail in %s on line %d
diff --git a/tests/classes/abstract_derived.phpt b/tests/classes/abstract_derived.phpt
new file mode 100644
index 0000000..0feceac
--- /dev/null
+++ b/tests/classes/abstract_derived.phpt
@@ -0,0 +1,20 @@
+--TEST--
+ZE2 A derived class with an abstract method must be abstract
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class base {
+}
+
+class derived extends base {
+ abstract function show();
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+
+Fatal error: Class derived contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (derived::show) in %sabstract_derived.php on line %d
diff --git a/tests/classes/abstract_final.phpt b/tests/classes/abstract_final.phpt
new file mode 100644
index 0000000..20c7ae3
--- /dev/null
+++ b/tests/classes/abstract_final.phpt
@@ -0,0 +1,16 @@
+--TEST--
+ZE2 A final method cannot be abstract
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class fail {
+ abstract final function show();
+}
+
+echo "Done\n"; // Shouldn't be displayed
+?>
+--EXPECTF--
+
+Fatal error: Cannot use the final modifier on an abstract class member in %s on line %d
diff --git a/tests/classes/abstract_inherit.phpt b/tests/classes/abstract_inherit.phpt
new file mode 100644
index 0000000..362ccb0
--- /dev/null
+++ b/tests/classes/abstract_inherit.phpt
@@ -0,0 +1,22 @@
+--TEST--
+ZE2 A class that inherits an abstract method is abstract
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+abstract class pass {
+ abstract function show();
+}
+
+abstract class fail extends pass {
+}
+
+$t = new fail();
+$t = new pass();
+
+echo "Done\n"; // Shouldn't be displayed
+?>
+--EXPECTF--
+
+Fatal error: Cannot instantiate abstract class fail in %s on line %d
diff --git a/tests/classes/abstract_not_declared.phpt b/tests/classes/abstract_not_declared.phpt
new file mode 100644
index 0000000..3b81cd4
--- /dev/null
+++ b/tests/classes/abstract_not_declared.phpt
@@ -0,0 +1,15 @@
+--TEST--
+ZE2 An abstract class must be declared abstract
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class fail {
+ abstract function show();
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (fail::show) in %s on line %d
diff --git a/tests/classes/abstract_redeclare.phpt b/tests/classes/abstract_redeclare.phpt
new file mode 100644
index 0000000..9a0a1ed
--- /dev/null
+++ b/tests/classes/abstract_redeclare.phpt
@@ -0,0 +1,22 @@
+--TEST--
+ZE2 A method cannot be redeclared abstract
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ function show() {
+ echo "Call to function show()\n";
+ }
+}
+
+class fail extends pass {
+ abstract function show();
+}
+
+echo "Done\n"; // Shouldn't be displayed
+?>
+--EXPECTF--
+
+Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (fail::show) in %sabstract_redeclare.php on line %d
diff --git a/tests/classes/abstract_static.phpt b/tests/classes/abstract_static.phpt
new file mode 100644
index 0000000..bcebec5
--- /dev/null
+++ b/tests/classes/abstract_static.phpt
@@ -0,0 +1,36 @@
+--TEST--
+ZE2 A static abstract methods
+--FILE--
+<?php
+
+interface showable
+{
+ static function show();
+}
+
+class pass implements showable
+{
+ static function show() {
+ echo "Call to function show()\n";
+ }
+}
+
+pass::show();
+
+eval('
+class fail
+{
+ abstract static function func();
+}
+');
+
+fail::show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call to function show()
+
+Strict Standards: Static function fail::func() should not be abstract in %sabstract_static.php(%d) : eval()'d code on line %d
+
+Fatal error: Class fail contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (fail::func) in %sabstract_static.php(%d) : eval()'d code on line %d
diff --git a/tests/classes/abstract_user_call.phpt b/tests/classes/abstract_user_call.phpt
new file mode 100644
index 0000000..0e1ddbe
--- /dev/null
+++ b/tests/classes/abstract_user_call.phpt
@@ -0,0 +1,30 @@
+--TEST--
+ZE2 An abstrcat method cannot be called indirectly
+--FILE--
+<?php
+
+abstract class test_base
+{
+ abstract function func();
+}
+
+class test extends test_base
+{
+ function func()
+ {
+ echo __METHOD__ . "()\n";
+ }
+}
+
+$o = new test;
+
+$o->func();
+
+call_user_func(array($o, 'test_base::func'));
+
+?>
+===DONE===
+--EXPECTF--
+test::func()
+
+Fatal error: Cannot call abstract method test_base::func() in %s on line %d
diff --git a/tests/classes/array_access_001.phpt b/tests/classes/array_access_001.phpt
new file mode 100644
index 0000000..feed3fb
--- /dev/null
+++ b/tests/classes/array_access_001.phpt
@@ -0,0 +1,198 @@
+--TEST--
+ZE2 ArrayAccess
+--FILE--
+<?php
+class object implements ArrayAccess {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+ function offsetExists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $this->a);
+ }
+ function offsetGet($index) {
+ echo __METHOD__ . "($index)\n";
+ return $this->a[$index];
+ }
+ function offsetSet($index, $newval) {
+ echo __METHOD__ . "($index,$newval)\n";
+ return $this->a[$index] = $newval;
+ }
+ function offsetUnset($index) {
+ echo __METHOD__ . "($index)\n";
+ unset($this->a[$index]);
+ }
+}
+
+$obj = new Object;
+
+var_dump($obj->a);
+
+echo "===EMPTY===\n";
+var_dump(empty($obj[0]));
+var_dump(empty($obj[1]));
+var_dump(empty($obj[2]));
+var_dump(empty($obj['4th']));
+var_dump(empty($obj['5th']));
+var_dump(empty($obj[6]));
+
+echo "===isset===\n";
+var_dump(isset($obj[0]));
+var_dump(isset($obj[1]));
+var_dump(isset($obj[2]));
+var_dump(isset($obj['4th']));
+var_dump(isset($obj['5th']));
+var_dump(isset($obj[6]));
+
+echo "===offsetGet===\n";
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "===offsetSet===\n";
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+echo "===unset===\n";
+var_dump($obj->a);
+unset($obj[2]);
+unset($obj['4th']);
+unset($obj[7]);
+unset($obj['8th']);
+var_dump($obj->a);
+
+?>
+===DONE===
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+===EMPTY===
+object::offsetExists(0)
+object::offsetGet(0)
+bool(false)
+object::offsetExists(1)
+object::offsetGet(1)
+bool(false)
+object::offsetExists(2)
+object::offsetGet(2)
+bool(false)
+object::offsetExists(4th)
+object::offsetGet(4th)
+bool(false)
+object::offsetExists(5th)
+bool(true)
+object::offsetExists(6)
+bool(true)
+===isset===
+object::offsetExists(0)
+bool(true)
+object::offsetExists(1)
+bool(true)
+object::offsetExists(2)
+bool(true)
+object::offsetExists(4th)
+bool(true)
+object::offsetExists(5th)
+bool(false)
+object::offsetExists(6)
+bool(false)
+===offsetGet===
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(1)
+int(1)
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetGet(4th)
+int(4)
+object::offsetGet(5th)
+
+Notice: Undefined index: 5th in %sarray_access_001.php on line %d
+NULL
+object::offsetGet(6)
+
+Notice: Undefined offset: 6 in %sarray_access_001.php on line %d
+NULL
+===offsetSet===
+WRITE 1
+object::offsetSet(1,Changed 1)
+object::offsetGet(1)
+string(9) "Changed 1"
+WRITE 2
+object::offsetSet(4th,Changed 4th)
+object::offsetGet(4th)
+string(11) "Changed 4th"
+WRITE 3
+object::offsetSet(5th,Added 5th)
+object::offsetGet(5th)
+string(9) "Added 5th"
+WRITE 4
+object::offsetSet(6,Added 6)
+object::offsetGet(6)
+string(7) "Added 6"
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetSet(6,changed 6)
+object::offsetGet(6)
+string(9) "changed 6"
+string(9) "changed 6"
+===unset===
+array(6) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ string(9) "Changed 1"
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ string(11) "Changed 4th"
+ ["5th"]=>
+ string(9) "Added 5th"
+ [6]=>
+ string(9) "changed 6"
+}
+object::offsetUnset(2)
+object::offsetUnset(4th)
+object::offsetUnset(7)
+object::offsetUnset(8th)
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ string(9) "Changed 1"
+ ["5th"]=>
+ string(9) "Added 5th"
+ [6]=>
+ string(9) "changed 6"
+}
+===DONE===
diff --git a/tests/classes/array_access_002.phpt b/tests/classes/array_access_002.phpt
new file mode 100644
index 0000000..68640c8
--- /dev/null
+++ b/tests/classes/array_access_002.phpt
@@ -0,0 +1,198 @@
+--TEST--
+ZE2 ArrayAccess::offsetSet without return
+--FILE--
+<?php
+class object implements ArrayAccess {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+ function offsetExists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $this->a);
+ }
+ function offsetGet($index) {
+ echo __METHOD__ . "($index)\n";
+ return $this->a[$index];
+ }
+ function offsetSet($index, $newval) {
+ echo __METHOD__ . "($index,$newval)\n";
+ /*return*/ $this->a[$index] = $newval;
+ }
+ function offsetUnset($index) {
+ echo __METHOD__ . "($index)\n";
+ unset($this->a[$index]);
+ }
+}
+
+$obj = new Object;
+
+var_dump($obj->a);
+
+echo "===EMPTY===\n";
+var_dump(empty($obj[0]));
+var_dump(empty($obj[1]));
+var_dump(empty($obj[2]));
+var_dump(empty($obj['4th']));
+var_dump(empty($obj['5th']));
+var_dump(empty($obj[6]));
+
+echo "===isset===\n";
+var_dump(isset($obj[0]));
+var_dump(isset($obj[1]));
+var_dump(isset($obj[2]));
+var_dump(isset($obj['4th']));
+var_dump(isset($obj['5th']));
+var_dump(isset($obj[6]));
+
+echo "===offsetGet===\n";
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "===offsetSet===\n";
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+echo "===unset===\n";
+var_dump($obj->a);
+unset($obj[2]);
+unset($obj['4th']);
+unset($obj[7]);
+unset($obj['8th']);
+var_dump($obj->a);
+
+?>
+===DONE===
+--EXPECTF--
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ int(1)
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ int(4)
+}
+===EMPTY===
+object::offsetExists(0)
+object::offsetGet(0)
+bool(false)
+object::offsetExists(1)
+object::offsetGet(1)
+bool(false)
+object::offsetExists(2)
+object::offsetGet(2)
+bool(false)
+object::offsetExists(4th)
+object::offsetGet(4th)
+bool(false)
+object::offsetExists(5th)
+bool(true)
+object::offsetExists(6)
+bool(true)
+===isset===
+object::offsetExists(0)
+bool(true)
+object::offsetExists(1)
+bool(true)
+object::offsetExists(2)
+bool(true)
+object::offsetExists(4th)
+bool(true)
+object::offsetExists(5th)
+bool(false)
+object::offsetExists(6)
+bool(false)
+===offsetGet===
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(1)
+int(1)
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetGet(4th)
+int(4)
+object::offsetGet(5th)
+
+Notice: Undefined index: 5th in %sarray_access_002.php on line %d
+NULL
+object::offsetGet(6)
+
+Notice: Undefined offset: 6 in %sarray_access_002.php on line %d
+NULL
+===offsetSet===
+WRITE 1
+object::offsetSet(1,Changed 1)
+object::offsetGet(1)
+string(9) "Changed 1"
+WRITE 2
+object::offsetSet(4th,Changed 4th)
+object::offsetGet(4th)
+string(11) "Changed 4th"
+WRITE 3
+object::offsetSet(5th,Added 5th)
+object::offsetGet(5th)
+string(9) "Added 5th"
+WRITE 4
+object::offsetSet(6,Added 6)
+object::offsetGet(6)
+string(7) "Added 6"
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetSet(6,changed 6)
+object::offsetGet(6)
+string(9) "changed 6"
+string(9) "changed 6"
+===unset===
+array(6) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ string(9) "Changed 1"
+ [2]=>
+ string(3) "3rd"
+ ["4th"]=>
+ string(11) "Changed 4th"
+ ["5th"]=>
+ string(9) "Added 5th"
+ [6]=>
+ string(9) "changed 6"
+}
+object::offsetUnset(2)
+object::offsetUnset(4th)
+object::offsetUnset(7)
+object::offsetUnset(8th)
+array(4) {
+ [0]=>
+ string(3) "1st"
+ [1]=>
+ string(9) "Changed 1"
+ ["5th"]=>
+ string(9) "Added 5th"
+ [6]=>
+ string(9) "changed 6"
+}
+===DONE===
diff --git a/tests/classes/array_access_003.phpt b/tests/classes/array_access_003.phpt
new file mode 100644
index 0000000..3e63112
--- /dev/null
+++ b/tests/classes/array_access_003.phpt
@@ -0,0 +1,59 @@
+--TEST--
+ZE2 ArrayAccess::offsetGet ambiguties
+--INI--
+error_reporting=4095
+--FILE--
+<?php
+class object implements ArrayAccess {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+ function offsetExists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $this->a);
+ }
+ function offsetGet($index) {
+ echo __METHOD__ . "($index)\n";
+ switch($index) {
+ case 1:
+ $a = 'foo';
+ return $a . 'Bar';
+ case 2:
+ static $a=1;
+ return $a;
+ }
+ return $this->a[$index];
+ }
+ function offsetSet($index, $newval) {
+ echo __METHOD__ . "($index,$newval)\n";
+ if ($index==3) {
+ $this->cnt = $newval;
+ }
+ return $this->a[$index] = $newval;
+ }
+ function offsetUnset($index) {
+ echo __METHOD__ . "($index)\n";
+ unset($this->a[$index]);
+ }
+}
+
+$obj = new Object;
+
+var_dump($obj[1]);
+var_dump($obj[2]);
+$obj[2]++;
+var_dump($obj[2]);
+
+?>
+===DONE===
+--EXPECTF--
+object::offsetGet(1)
+string(6) "fooBar"
+object::offsetGet(2)
+int(1)
+object::offsetGet(2)
+
+Notice: Indirect modification of overloaded element of object has no effect in %sarray_access_003.php on line 39
+object::offsetGet(2)
+int(1)
+===DONE===
diff --git a/tests/classes/array_access_004.phpt b/tests/classes/array_access_004.phpt
new file mode 100644
index 0000000..7874967
--- /dev/null
+++ b/tests/classes/array_access_004.phpt
@@ -0,0 +1,57 @@
+--TEST--
+ZE2 ArrayAccess::offsetGet ambiguties
+--FILE--
+<?php
+class object implements ArrayAccess {
+
+ public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+ function offsetExists($index) {
+ echo __METHOD__ . "($index)\n";
+ return array_key_exists($index, $this->a);
+ }
+ function offsetGet($index) {
+ echo __METHOD__ . "($index)\n";
+ switch($index) {
+ case 1:
+ $a = 'foo';
+ return $a . 'Bar';
+ case 2:
+ static $a=1;
+ return $a;
+ }
+ return $this->a[$index];
+ }
+ function offsetSet($index, $newval) {
+ echo __METHOD__ . "($index,$newval)\n";
+ if ($index==3) {
+ $this->cnt = $newval;
+ }
+ return $this->a[$index] = $newval;
+ }
+ function offsetUnset($index) {
+ echo __METHOD__ . "($index)\n";
+ unset($this->a[$index]);
+ }
+}
+
+$obj = new Object;
+
+var_dump($obj[1]);
+var_dump($obj[2]);
+$obj[2]++;
+var_dump($obj[2]);
+
+?>
+===DONE===
+--EXPECTF--
+object::offsetGet(1)
+string(6) "fooBar"
+object::offsetGet(2)
+int(1)
+object::offsetGet(2)
+
+Notice: Indirect modification of overloaded element of object has no effect in %sarray_access_004.php on line 39
+object::offsetGet(2)
+int(1)
+===DONE===
diff --git a/tests/classes/array_access_005.phpt b/tests/classes/array_access_005.phpt
new file mode 100644
index 0000000..dcb873f
--- /dev/null
+++ b/tests/classes/array_access_005.phpt
@@ -0,0 +1,77 @@
+--TEST--
+ZE2 ArrayAccess and sub Arrays
+--FILE--
+<?php
+
+class Peoples implements ArrayAccess {
+ public $person;
+
+ function __construct() {
+ $this->person = array(array('name'=>'Joe'));
+ }
+
+ function offsetExists($index) {
+ return array_key_exists($this->person, $index);
+ }
+
+ function offsetGet($index) {
+ return $this->person[$index];
+ }
+
+ function offsetSet($index, $value) {
+ $this->person[$index] = $value;
+ }
+
+ function offsetUnset($index) {
+ unset($this->person[$index]);
+ }
+}
+
+$people = new Peoples;
+
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] = $people->person[0]['name'] . 'Foo';
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] .= 'Bar';
+var_dump($people->person[0]['name']);
+
+echo "---ArrayOverloading---\n";
+
+$people = new Peoples;
+
+var_dump($people[0]);
+var_dump($people[0]['name']);
+var_dump($people->person[0]['name'] . 'Foo'); // impossible to assign this since we don't return references here
+$x = $people[0]; // creates a copy
+$x['name'] .= 'Foo';
+$people[0] = $x;
+var_dump($people[0]);
+$people[0]['name'] = 'JoeFoo';
+var_dump($people[0]['name']);
+$people[0]['name'] = 'JoeFooBar';
+var_dump($people[0]['name']);
+
+?>
+===DONE===
+--EXPECTF--
+string(3) "Joe"
+string(6) "JoeFoo"
+string(9) "JoeFooBar"
+---ArrayOverloading---
+array(1) {
+ ["name"]=>
+ string(3) "Joe"
+}
+string(3) "Joe"
+string(6) "JoeFoo"
+array(1) {
+ ["name"]=>
+ string(6) "JoeFoo"
+}
+
+Notice: Indirect modification of overloaded element of Peoples has no effect in %sarray_access_005.php on line 46
+string(6) "JoeFoo"
+
+Notice: Indirect modification of overloaded element of Peoples has no effect in %sarray_access_005.php on line 48
+string(6) "JoeFoo"
+===DONE===
diff --git a/tests/classes/array_access_006.phpt b/tests/classes/array_access_006.phpt
new file mode 100644
index 0000000..342a7e5
--- /dev/null
+++ b/tests/classes/array_access_006.phpt
@@ -0,0 +1,37 @@
+--TEST--
+ZE2 ArrayAccess and ASSIGN_OP operators (+=)
+--FILE--
+<?php
+
+class OverloadedArray implements ArrayAccess {
+ public $realArray;
+
+ function __construct() {
+ $this->realArray = array(1,2,3);
+ }
+
+ function offsetExists($index) {
+ return array_key_exists($this->realArray, $index);
+ }
+
+ function offsetGet($index) {
+ return $this->realArray[$index];
+ }
+
+ function offsetSet($index, $value) {
+ $this->realArray[$index] = $value;
+ }
+
+ function offsetUnset($index) {
+ unset($this->realArray[$index]);
+ }
+}
+
+$a = new OverloadedArray;
+$a[1] += 10;
+var_dump($a[1]);
+echo "---Done---\n";
+?>
+--EXPECT--
+int(12)
+---Done---
diff --git a/tests/classes/array_access_007.phpt b/tests/classes/array_access_007.phpt
new file mode 100644
index 0000000..42187fe
--- /dev/null
+++ b/tests/classes/array_access_007.phpt
@@ -0,0 +1,57 @@
+--TEST--
+ZE2 ArrayAccess and [] assignment
+--FILE--
+<?php
+
+class OverloadedArray implements ArrayAccess {
+ public $realArray;
+
+ function __construct() {
+ $this->realArray = array();
+ }
+
+ function offsetExists($index) {
+ return array_key_exists($this->realArray, $index);
+ }
+
+ function offsetGet($index) {
+ return $this->realArray[$index];
+ }
+
+ function offsetSet($index, $value) {
+ if (is_null($index)) {
+ $this->realArray[] = $value;
+ } else {
+ $this->realArray[$index] = $value;
+ }
+ }
+
+ function offsetUnset($index) {
+ unset($this->realArray[$index]);
+ }
+
+ function dump() {
+ var_dump($this->realArray);
+ }
+}
+
+$a = new OverloadedArray;
+$a[] = 1;
+$a[1] = 2;
+$a[2] = 3;
+$a[] = 4;
+$a->dump();
+?>
+===DONE===
+--EXPECT--
+array(4) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ [3]=>
+ int(4)
+}
+===DONE===
diff --git a/tests/classes/array_access_008.phpt b/tests/classes/array_access_008.phpt
new file mode 100644
index 0000000..9979889
--- /dev/null
+++ b/tests/classes/array_access_008.phpt
@@ -0,0 +1,67 @@
+--TEST--
+ZE2 ArrayAccess and ASSIGN_OP operators (.=)
+--FILE--
+<?php
+
+class Peoples implements ArrayAccess {
+ public $person;
+
+ function __construct() {
+ $this->person = array(array('name'=>'Foo'));
+ }
+
+ function offsetExists($index) {
+ return array_key_exists($this->person, $index);
+ }
+
+ function offsetGet($index) {
+ return $this->person[$index];
+ }
+
+ function offsetSet($index, $value) {
+ $this->person[$index] = $value;
+ }
+
+ function offsetUnset($index) {
+ unset($this->person[$index]);
+ }
+}
+
+$people = new Peoples;
+
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] .= 'Baz';
+var_dump($people->person[0]['name']);
+
+echo "===ArrayOverloading===\n";
+
+$people = new Peoples;
+
+var_dump($people[0]['name']);
+$people[0]['name'] = 'FooBar';
+var_dump($people[0]['name']);
+$people[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people[0]['name']);
+$people[0]['name'] .= 'Baz';
+var_dump($people[0]['name']);
+
+?>
+===DONE===
+--EXPECTF--
+string(3) "Foo"
+string(6) "FooBar"
+string(9) "FooBarBaz"
+===ArrayOverloading===
+string(3) "Foo"
+
+Notice: Indirect modification of overloaded element of Peoples has no effect in %sarray_access_008.php on line 40
+string(3) "Foo"
+
+Notice: Indirect modification of overloaded element of Peoples has no effect in %sarray_access_008.php on line 42
+string(3) "Foo"
+
+Notice: Indirect modification of overloaded element of Peoples has no effect in %sarray_access_008.php on line 44
+string(3) "Foo"
+===DONE===
diff --git a/tests/classes/array_access_009.phpt b/tests/classes/array_access_009.phpt
new file mode 100644
index 0000000..3862240
--- /dev/null
+++ b/tests/classes/array_access_009.phpt
@@ -0,0 +1,190 @@
+--TEST--
+ZE2 ArrayAccess and ArrayProxyAccess, ArrayProxy
+--FILE--
+<?php
+
+// NOTE: This will become part of SPL
+
+interface ArrayProxyAccess extends ArrayAccess
+{
+ function proxyGet($element);
+ function proxySet($element, $index, $value);
+ function proxyUnset($element, $index);
+}
+
+class ArrayProxy implements ArrayAccess
+{
+ private $object;
+ private $element;
+
+ function __construct(ArrayProxyAccess $object, $element)
+ {
+ echo __METHOD__ . "($element)\n";
+ if (!$object->offsetExists($element))
+ {
+ $object[$element] = array();
+ }
+ $this->object = $object;
+ $this->element = $element;
+ }
+
+ function offsetExists($index) {
+ echo __METHOD__ . "($this->element, $index)\n";
+ return array_key_exists($index, $this->object->proxyGet($this->element));
+ }
+
+ function offsetGet($index) {
+ echo __METHOD__ . "($this->element, $index)\n";
+ $tmp = $this->object->proxyGet($this->element);
+ return isset($tmp[$index]) ? $tmp[$index] : NULL;
+ }
+
+ function offsetSet($index, $value) {
+ echo __METHOD__ . "($this->element, $index, $value)\n";
+ $this->object->proxySet($this->element, $index, $value);
+ }
+
+ function offsetUnset($index) {
+ echo __METHOD__ . "($this->element, $index)\n";
+ $this->object->proxyUnset($this->element, $index);
+ }
+}
+
+class Peoples implements ArrayProxyAccess
+{
+ public $person;
+
+ function __construct()
+ {
+ $this->person = array(array('name'=>'Foo'));
+ }
+
+ function offsetExists($index)
+ {
+ return array_key_exists($index, $this->person);
+ }
+
+ function offsetGet($index)
+ {
+ return new ArrayProxy($this, $index);
+ }
+
+ function offsetSet($index, $value)
+ {
+ $this->person[$index] = $value;
+ }
+
+ function offsetUnset($index)
+ {
+ unset($this->person[$index]);
+ }
+
+ function proxyGet($element)
+ {
+ return $this->person[$element];
+ }
+
+ function proxySet($element, $index, $value)
+ {
+ $this->person[$element][$index] = $value;
+ }
+
+ function proxyUnset($element, $index)
+ {
+ unset($this->person[$element][$index]);
+ }
+}
+
+$people = new Peoples;
+
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] .= 'Baz';
+var_dump($people->person[0]['name']);
+
+echo "===ArrayOverloading===\n";
+
+$people = new Peoples;
+
+var_dump($people[0]);
+var_dump($people[0]['name']);
+$people[0]['name'] = 'FooBar';
+var_dump($people[0]['name']);
+$people[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people[0]['name']);
+$people[0]['name'] .= 'Baz';
+var_dump($people[0]['name']);
+unset($people[0]['name']);
+var_dump($people[0]);
+var_dump($people[0]['name']);
+$people[0]['name'] = 'BlaBla';
+var_dump($people[0]['name']);
+
+?>
+===DONE===
+--EXPECTF--
+string(3) "Foo"
+string(6) "FooBar"
+string(9) "FooBarBaz"
+===ArrayOverloading===
+ArrayProxy::__construct(0)
+object(ArrayProxy)#%d (2) {
+ ["object":"ArrayProxy":private]=>
+ object(Peoples)#%d (1) {
+ ["person"]=>
+ array(1) {
+ [0]=>
+ array(1) {
+ ["name"]=>
+ string(3) "Foo"
+ }
+ }
+ }
+ ["element":"ArrayProxy":private]=>
+ int(0)
+}
+ArrayProxy::__construct(0)
+ArrayProxy::offsetGet(0, name)
+string(3) "Foo"
+ArrayProxy::__construct(0)
+ArrayProxy::offsetSet(0, name, FooBar)
+ArrayProxy::__construct(0)
+ArrayProxy::offsetGet(0, name)
+string(6) "FooBar"
+ArrayProxy::__construct(0)
+ArrayProxy::offsetSet(0, name, FooBarBar)
+ArrayProxy::__construct(0)
+ArrayProxy::offsetGet(0, name)
+string(9) "FooBarBar"
+ArrayProxy::__construct(0)
+ArrayProxy::offsetGet(0, name)
+ArrayProxy::offsetSet(0, name, FooBarBarBaz)
+ArrayProxy::__construct(0)
+ArrayProxy::offsetGet(0, name)
+string(12) "FooBarBarBaz"
+ArrayProxy::__construct(0)
+ArrayProxy::offsetUnset(0, name)
+ArrayProxy::__construct(0)
+object(ArrayProxy)#%d (2) {
+ ["object":"ArrayProxy":private]=>
+ object(Peoples)#%d (1) {
+ ["person"]=>
+ array(1) {
+ [0]=>
+ array(0) {
+ }
+ }
+ }
+ ["element":"ArrayProxy":private]=>
+ int(0)
+}
+ArrayProxy::__construct(0)
+ArrayProxy::offsetGet(0, name)
+NULL
+ArrayProxy::__construct(0)
+ArrayProxy::offsetSet(0, name, BlaBla)
+ArrayProxy::__construct(0)
+ArrayProxy::offsetGet(0, name)
+string(6) "BlaBla"
+===DONE===
diff --git a/tests/classes/array_access_010.phpt b/tests/classes/array_access_010.phpt
new file mode 100644
index 0000000..ad374d2
--- /dev/null
+++ b/tests/classes/array_access_010.phpt
@@ -0,0 +1,168 @@
+--TEST--
+ZE2 ArrayAccess and ArrayReferenceProxy with references
+--FILE--
+<?php
+
+// NOTE: This will become part of SPL
+
+class ArrayReferenceProxy implements ArrayAccess
+{
+ private $object;
+ private $element;
+
+ function __construct(ArrayAccess $object, array &$element)
+ {
+ echo __METHOD__ . "(Array)\n";
+ $this->object = $object;
+ $this->element = &$element;
+ }
+
+ function offsetExists($index) {
+ echo __METHOD__ . "($this->element, $index)\n";
+ return array_key_exists($index, $this->element);
+ }
+
+ function offsetGet($index) {
+ echo __METHOD__ . "(Array, $index)\n";
+ return isset($this->element[$index]) ? $this->element[$index] : NULL;
+ }
+
+ function offsetSet($index, $value) {
+ echo __METHOD__ . "(Array, $index, $value)\n";
+ $this->element[$index] = $value;
+ }
+
+ function offsetUnset($index) {
+ echo __METHOD__ . "(Array, $index)\n";
+ unset($this->element[$index]);
+ }
+}
+
+class Peoples implements ArrayAccess
+{
+ public $person;
+
+ function __construct()
+ {
+ $this->person = array(array('name'=>'Foo'));
+ }
+
+ function offsetExists($index)
+ {
+ return array_key_exists($index, $this->person);
+ }
+
+ function offsetGet($index)
+ {
+ return new ArrayReferenceProxy($this, $this->person[$index]);
+ }
+
+ function offsetSet($index, $value)
+ {
+ $this->person[$index] = $value;
+ }
+
+ function offsetUnset($index)
+ {
+ unset($this->person[$index]);
+ }
+}
+
+$people = new Peoples;
+
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] .= 'Baz';
+var_dump($people->person[0]['name']);
+
+echo "===ArrayOverloading===\n";
+
+$people = new Peoples;
+
+var_dump($people[0]);
+var_dump($people[0]['name']);
+$people[0]['name'] = 'FooBar';
+var_dump($people[0]['name']);
+$people[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people[0]['name']);
+$people[0]['name'] .= 'Baz';
+var_dump($people[0]['name']);
+unset($people[0]['name']);
+var_dump($people[0]);
+var_dump($people[0]['name']);
+$people[0]['name'] = 'BlaBla';
+var_dump($people[0]['name']);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(3) "Foo"
+string(6) "FooBar"
+string(9) "FooBarBaz"
+===ArrayOverloading===
+ArrayReferenceProxy::__construct(Array)
+object(ArrayReferenceProxy)#%d (2) {
+ ["object":"ArrayReferenceProxy":private]=>
+ object(Peoples)#%d (1) {
+ ["person"]=>
+ array(1) {
+ [0]=>
+ &array(1) {
+ ["name"]=>
+ string(3) "Foo"
+ }
+ }
+ }
+ ["element":"ArrayReferenceProxy":private]=>
+ &array(1) {
+ ["name"]=>
+ string(3) "Foo"
+ }
+}
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetGet(Array, name)
+string(3) "Foo"
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetSet(Array, name, FooBar)
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetGet(Array, name)
+string(6) "FooBar"
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetSet(Array, name, FooBarBar)
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetGet(Array, name)
+string(9) "FooBarBar"
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetGet(Array, name)
+ArrayReferenceProxy::offsetSet(Array, name, FooBarBarBaz)
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetGet(Array, name)
+string(12) "FooBarBarBaz"
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetUnset(Array, name)
+ArrayReferenceProxy::__construct(Array)
+object(ArrayReferenceProxy)#%d (2) {
+ ["object":"ArrayReferenceProxy":private]=>
+ object(Peoples)#%d (1) {
+ ["person"]=>
+ array(1) {
+ [0]=>
+ &array(0) {
+ }
+ }
+ }
+ ["element":"ArrayReferenceProxy":private]=>
+ &array(0) {
+ }
+}
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetGet(Array, name)
+NULL
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetSet(Array, name, BlaBla)
+ArrayReferenceProxy::__construct(Array)
+ArrayReferenceProxy::offsetGet(Array, name)
+string(6) "BlaBla"
+===DONE===
diff --git a/tests/classes/array_access_011.phpt b/tests/classes/array_access_011.phpt
new file mode 100644
index 0000000..aa20a56
--- /dev/null
+++ b/tests/classes/array_access_011.phpt
@@ -0,0 +1,187 @@
+--TEST--
+ZE2 ArrayAccess and ArrayAccessReferenceProxy with references to main array
+--FILE--
+<?php
+
+// NOTE: This will become part of SPL
+
+class ArrayAccessReferenceProxy implements ArrayAccess
+{
+ private $object;
+ private $oarray;
+ private $element;
+
+ function __construct(ArrayAccess $object, array &$array, $element)
+ {
+ echo __METHOD__ . "($element)\n";
+ $this->object = $object;
+ $this->oarray = &$array;
+ $this->element = $element;
+ }
+
+ function offsetExists($index) {
+ echo __METHOD__ . "($this->element, $index)\n";
+ return array_key_exists($index, $this->oarray[$this->element]);
+ }
+
+ function offsetGet($index) {
+ echo __METHOD__ . "($this->element, $index)\n";
+ return isset($this->oarray[$this->element][$index]) ? $this->oarray[$this->element][$index] : NULL;
+ }
+
+ function offsetSet($index, $value) {
+ echo __METHOD__ . "($this->element, $index, $value)\n";
+ $this->oarray[$this->element][$index] = $value;
+ }
+
+ function offsetUnset($index) {
+ echo __METHOD__ . "($this->element, $index)\n";
+ unset($this->oarray[$this->element][$index]);
+ }
+}
+
+class Peoples implements ArrayAccess
+{
+ public $person;
+
+ function __construct()
+ {
+ $this->person = array(array('name'=>'Foo'));
+ }
+
+ function offsetExists($index)
+ {
+ return array_key_exists($index, $this->person);
+ }
+
+ function offsetGet($index)
+ {
+ if (is_array($this->person[$index]))
+ {
+ return new ArrayAccessReferenceProxy($this, $this->person, $index);
+ }
+ else
+ {
+ return $this->person[$index];
+ }
+ }
+
+ function offsetSet($index, $value)
+ {
+ $this->person[$index] = $value;
+ }
+
+ function offsetUnset($index)
+ {
+ unset($this->person[$index]);
+ }
+}
+
+$people = new Peoples;
+
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people->person[0]['name']);
+$people->person[0]['name'] .= 'Baz';
+var_dump($people->person[0]['name']);
+
+echo "===ArrayOverloading===\n";
+
+$people = new Peoples;
+
+var_dump($people[0]);
+var_dump($people[0]['name']);
+$people[0]['name'] = 'FooBar';
+var_dump($people[0]['name']);
+$people[0]['name'] = $people->person[0]['name'] . 'Bar';
+var_dump($people[0]['name']);
+$people[0]['name'] .= 'Baz';
+var_dump($people[0]['name']);
+unset($people[0]['name']);
+var_dump($people[0]);
+var_dump($people[0]['name']);
+$people[0]['name'] = 'BlaBla';
+var_dump($people[0]['name']);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(3) "Foo"
+string(6) "FooBar"
+string(9) "FooBarBaz"
+===ArrayOverloading===
+ArrayAccessReferenceProxy::__construct(0)
+object(ArrayAccessReferenceProxy)#%d (3) {
+ ["object":"ArrayAccessReferenceProxy":private]=>
+ object(Peoples)#%d (1) {
+ ["person"]=>
+ &array(1) {
+ [0]=>
+ array(1) {
+ ["name"]=>
+ string(3) "Foo"
+ }
+ }
+ }
+ ["oarray":"ArrayAccessReferenceProxy":private]=>
+ &array(1) {
+ [0]=>
+ array(1) {
+ ["name"]=>
+ string(3) "Foo"
+ }
+ }
+ ["element":"ArrayAccessReferenceProxy":private]=>
+ int(0)
+}
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetGet(0, name)
+string(3) "Foo"
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetSet(0, name, FooBar)
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetGet(0, name)
+string(6) "FooBar"
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetSet(0, name, FooBarBar)
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetGet(0, name)
+string(9) "FooBarBar"
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetGet(0, name)
+ArrayAccessReferenceProxy::offsetSet(0, name, FooBarBarBaz)
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetGet(0, name)
+string(12) "FooBarBarBaz"
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetUnset(0, name)
+ArrayAccessReferenceProxy::__construct(0)
+object(ArrayAccessReferenceProxy)#%d (3) {
+ ["object":"ArrayAccessReferenceProxy":private]=>
+ object(Peoples)#%d (1) {
+ ["person"]=>
+ &array(1) {
+ [0]=>
+ array(0) {
+ }
+ }
+ }
+ ["oarray":"ArrayAccessReferenceProxy":private]=>
+ &array(1) {
+ [0]=>
+ array(0) {
+ }
+ }
+ ["element":"ArrayAccessReferenceProxy":private]=>
+ int(0)
+}
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetGet(0, name)
+NULL
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetSet(0, name, BlaBla)
+ArrayAccessReferenceProxy::__construct(0)
+ArrayAccessReferenceProxy::offsetGet(0, name)
+string(6) "BlaBla"
+===DONE===
diff --git a/tests/classes/array_access_012.phpt b/tests/classes/array_access_012.phpt
new file mode 100644
index 0000000..8f85f29
--- /dev/null
+++ b/tests/classes/array_access_012.phpt
@@ -0,0 +1,36 @@
+--TEST--
+ZE2 ArrayAccess cannot assign by reference
+--FILE--
+<?php
+
+class ArrayAccessImpl implements ArrayAccess {
+ private $data = array();
+
+ public function offsetUnset($index) {}
+
+ public function offsetSet($index, $value) {
+ $this->data[$index] = $value;
+ }
+
+ public function offsetGet($index) {
+ return $this->data[$index];
+ }
+
+ public function offsetExists($index) {
+ return isset($this->data[$index]);
+ }
+}
+
+$data = new ArrayAccessImpl();
+$test = 'some data';
+$data['element'] = NULL; // prevent notice
+$data['element'] = &$test;
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+
+Notice: Indirect modification of overloaded element of ArrayAccessImpl has no effect in %sarray_access_012.php on line 24
+
+Fatal error: Cannot assign by reference to overloaded object in %sarray_access_012.php on line 24
diff --git a/tests/classes/array_access_013.phpt b/tests/classes/array_access_013.phpt
new file mode 100644
index 0000000..206d9d5
--- /dev/null
+++ b/tests/classes/array_access_013.phpt
@@ -0,0 +1,58 @@
+--TEST--
+ZE2 ArrayAccess and exceptions
+--FILE--
+<?php
+
+class Test implements ArrayAccess
+{
+ public function offsetExists($offset) { throw new Exception(__METHOD__); return false; }
+ public function offsetGet($offset) { throw new Exception(__METHOD__); return $offset; }
+ public function offsetSet($offset, $data ) { throw new Exception(__METHOD__); }
+ public function offsetUnset($offset) { throw new Exception(__METHOD__); }
+}
+
+$t = new Test;
+
+try
+{
+ echo isset($t[0]);
+}
+catch(Exception $e)
+{
+ echo "Caught in " . $e->getMessage() . "()\n";
+}
+
+try
+{
+ echo $t[0];
+}
+catch(Exception $e)
+{
+ echo "Caught in " . $e->getMessage() . "()\n";
+}
+
+try
+{
+ $t[0] = 1;
+}
+catch(Exception $e)
+{
+ echo "Caught in " . $e->getMessage() . "()\n";
+}
+
+try
+{
+ unset($t[0]);
+}
+catch(Exception $e)
+{
+ echo "Caught in " . $e->getMessage() . "()\n";
+}
+?>
+===DONE===
+--EXPECT--
+Caught in Test::offsetExists()
+Caught in Test::offsetGet()
+Caught in Test::offsetSet()
+Caught in Test::offsetUnset()
+===DONE===
diff --git a/tests/classes/arrayobject_001.phpt b/tests/classes/arrayobject_001.phpt
new file mode 100644
index 0000000..b75f8c7
--- /dev/null
+++ b/tests/classes/arrayobject_001.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Ensure that ArrayObject acts like an array
+--FILE--
+<?php
+
+$a = new ArrayObject;
+$a['foo'] = 'bar';
+echo reset($a);
+echo count($a);
+echo current($a);
+?>
+--EXPECT--
+bar1bar
diff --git a/tests/classes/assign_op_property_001.phpt b/tests/classes/assign_op_property_001.phpt
new file mode 100644
index 0000000..21e131c
--- /dev/null
+++ b/tests/classes/assign_op_property_001.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 assign_op property of overloaded object
+--FILE--
+<?php
+
+class Test {
+ private $real_a = 2;
+
+ function __set($property, $value) {
+ if ($property == "a") {
+ $this->real_a = $value;
+ }
+ }
+
+ function __get($property) {
+ if ($property == "a") {
+ return $this->real_a;
+ }
+ }
+}
+
+$obj = new Test;
+var_dump($obj->a);
+$obj->a += 2;
+var_dump($obj->a);
+echo "---Done---\n";
+?>
+--EXPECT--
+int(2)
+int(4)
+---Done---
diff --git a/tests/classes/autoload_001.phpt b/tests/classes/autoload_001.phpt
new file mode 100644
index 0000000..6f325f4
--- /dev/null
+++ b/tests/classes/autoload_001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+ZE2 Autoload and class_exists
+--SKIPIF--
+<?php
+ if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed');
+ if (class_exists('autoload_root', false)) die('skip Autoload test classes exist already');
+?>
+--FILE--
+<?php
+
+function __autoload($class_name)
+{
+ require_once(dirname(__FILE__) . '/' . $class_name . '.p5c');
+ echo __FUNCTION__ . '(' . $class_name . ")\n";
+}
+
+var_dump(class_exists('autoload_root'));
+
+?>
+===DONE===
+--EXPECT--
+__autoload(autoload_root)
+bool(true)
+===DONE===
diff --git a/tests/classes/autoload_002.phpt b/tests/classes/autoload_002.phpt
new file mode 100644
index 0000000..27dea0f
--- /dev/null
+++ b/tests/classes/autoload_002.phpt
@@ -0,0 +1,27 @@
+--TEST--
+ZE2 Autoload and get_class_methods
+--SKIPIF--
+<?php
+ if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed');
+ if (class_exists('autoload_root', false)) die('skip Autoload test classes exist already');
+?>
+--FILE--
+<?php
+
+function __autoload($class_name)
+{
+ require_once(dirname(__FILE__) . '/' . $class_name . '.p5c');
+ echo __FUNCTION__ . '(' . $class_name . ")\n";
+}
+
+var_dump(get_class_methods('autoload_root'));
+
+?>
+===DONE===
+--EXPECT--
+__autoload(autoload_root)
+array(1) {
+ [0]=>
+ string(12) "testFunction"
+}
+===DONE===
diff --git a/tests/classes/autoload_003.phpt b/tests/classes/autoload_003.phpt
new file mode 100644
index 0000000..7bdb5da
--- /dev/null
+++ b/tests/classes/autoload_003.phpt
@@ -0,0 +1,25 @@
+--TEST--
+ZE2 Autoload and derived classes
+--SKIPIF--
+<?php
+ if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed');
+ if (class_exists('autoload_root', false)) die('skip Autoload test classes exist already');
+?>
+--FILE--
+<?php
+
+function __autoload($class_name)
+{
+ require_once(dirname(__FILE__) . '/' . $class_name . '.p5c');
+ echo __FUNCTION__ . '(' . $class_name . ")\n";
+}
+
+var_dump(class_exists('autoload_derived'));
+
+?>
+===DONE===
+--EXPECT--
+__autoload(autoload_root)
+__autoload(autoload_derived)
+bool(true)
+===DONE===
diff --git a/tests/classes/autoload_004.phpt b/tests/classes/autoload_004.phpt
new file mode 100644
index 0000000..23aea5d
--- /dev/null
+++ b/tests/classes/autoload_004.phpt
@@ -0,0 +1,28 @@
+--TEST--
+ZE2 Autoload and recursion
+--SKIPIF--
+<?php
+ if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed');
+ if (class_exists('autoload_root', false)) die('skip Autoload test classes exist already');
+?>
+--FILE--
+<?php
+
+function __autoload($class_name)
+{
+ var_dump(class_exists($class_name));
+ require_once(dirname(__FILE__) . '/' . $class_name . '.p5c');
+ echo __FUNCTION__ . '(' . $class_name . ")\n";
+}
+
+var_dump(class_exists('autoload_derived'));
+
+?>
+===DONE===
+--EXPECT--
+bool(false)
+bool(false)
+__autoload(autoload_root)
+__autoload(autoload_derived)
+bool(true)
+===DONE===
diff --git a/tests/classes/autoload_005.phpt b/tests/classes/autoload_005.phpt
new file mode 100644
index 0000000..36a4e18
--- /dev/null
+++ b/tests/classes/autoload_005.phpt
@@ -0,0 +1,45 @@
+--TEST--
+ZE2 Autoload from destructor
+--SKIPIF--
+<?php
+ if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed');
+ if (class_exists('autoload_root', false)) die('skip Autoload test classes exist already');
+?>
+--FILE--
+<?php
+
+function __autoload($class_name)
+{
+ var_dump(class_exists($class_name, false));
+ require_once(dirname(__FILE__) . '/' . $class_name . '.p5c');
+ echo __FUNCTION__ . '(' . $class_name . ")\n";
+}
+
+var_dump(class_exists('autoload_derived', false));
+var_dump(class_exists('autoload_derived', false));
+
+class Test
+{
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ $o = new autoload_derived;
+ var_dump($o);
+ }
+}
+
+$o = new Test;
+unset($o);
+
+?>
+===DONE===
+--EXPECTF--
+bool(false)
+bool(false)
+Test::__destruct
+bool(false)
+bool(false)
+__autoload(autoload_root)
+__autoload(autoload_derived)
+object(autoload_derived)#%d (0) {
+}
+===DONE===
diff --git a/tests/classes/autoload_006.phpt b/tests/classes/autoload_006.phpt
new file mode 100644
index 0000000..9af6fc9
--- /dev/null
+++ b/tests/classes/autoload_006.phpt
@@ -0,0 +1,40 @@
+--TEST--
+ZE2 Autoload from destructor
+--SKIPIF--
+<?php
+ if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed');
+ if (class_exists('autoload_root', false)) die('skip Autoload test classes exist already');
+?>
+--FILE--
+<?php
+
+function __autoload($class_name)
+{
+ require_once(dirname(__FILE__) . '/' . strtolower($class_name) . '.p5c');
+ echo __FUNCTION__ . '(' . $class_name . ")\n";
+}
+
+var_dump(interface_exists('autoload_interface', false));
+var_dump(class_exists('autoload_implements', false));
+
+$o = new Autoload_Implements;
+var_dump($o);
+var_dump($o instanceof autoload_interface);
+unset($o);
+
+var_dump(interface_exists('autoload_interface', false));
+var_dump(class_exists('autoload_implements', false));
+
+?>
+===DONE===
+--EXPECTF--
+bool(false)
+bool(false)
+__autoload(autoload_interface)
+__autoload(Autoload_Implements)
+object(autoload_implements)#%d (0) {
+}
+bool(true)
+bool(true)
+bool(true)
+===DONE===
diff --git a/tests/classes/autoload_007.phpt b/tests/classes/autoload_007.phpt
new file mode 100644
index 0000000..5652c12
--- /dev/null
+++ b/tests/classes/autoload_007.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Ensure instanceof does not trigger autoload.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ $a = new stdClass;
+ var_dump($a instanceof UndefC);
+?>
+--EXPECTF--
+bool(false)
diff --git a/tests/classes/autoload_008.phpt b/tests/classes/autoload_008.phpt
new file mode 100644
index 0000000..75a9cd0
--- /dev/null
+++ b/tests/classes/autoload_008.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Ensure catch blocks for unknown exception types do not trigger autoload.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ function f()
+ {
+ throw new Exception();
+ }
+ try {
+ f();
+ }
+ catch (UndefC $u) {
+ echo "In UndefClass catch block.\n";
+ }
+ catch (Exception $e) {
+ echo "In Exception catch block. Autoload should not have been triggered.\n";
+ }
+?>
+--EXPECTF--
+In Exception catch block. Autoload should not have been triggered.
diff --git a/tests/classes/autoload_009.phpt b/tests/classes/autoload_009.phpt
new file mode 100644
index 0000000..46f6055
--- /dev/null
+++ b/tests/classes/autoload_009.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Ensure type hints for unknown types do not trigger autoload.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ function f(UndefClass $x)
+ {
+ }
+ f(new stdClass);
+?>
+--EXPECTF--
+
+Catchable fatal error: Argument 1 passed to f() must be an instance of UndefClass, instance of stdClass given, called in %s
+
+
diff --git a/tests/classes/autoload_010.phpt b/tests/classes/autoload_010.phpt
new file mode 100644
index 0000000..104f688
--- /dev/null
+++ b/tests/classes/autoload_010.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Ensure implements does trigger autoload.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ class C implements UndefI
+ {
+ }
+?>
+--EXPECTF--
+In autoload: string(6) "UndefI"
+
+Fatal error: Interface 'UndefI' not found in %s on line %d
diff --git a/tests/classes/autoload_011.phpt b/tests/classes/autoload_011.phpt
new file mode 100644
index 0000000..86858d5
--- /dev/null
+++ b/tests/classes/autoload_011.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Ensure extends does trigger autoload.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ class C extends UndefBase
+ {
+ }
+?>
+--EXPECTF--
+In autoload: string(9) "UndefBase"
+
+Fatal error: Class 'UndefBase' not found in %s on line %d
diff --git a/tests/classes/autoload_012.phpt b/tests/classes/autoload_012.phpt
new file mode 100644
index 0000000..d6750b7
--- /dev/null
+++ b/tests/classes/autoload_012.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Ensure callback methods in unknown classes trigger autoload.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+ call_user_func("UndefC::test");
+?>
+--EXPECTF--
+In autoload: string(6) "UndefC"
+
+Warning: call_user_func() expects parameter 1 to be a valid callback, class 'UndefC' not found in %s on line %d
diff --git a/tests/classes/autoload_013.phpt b/tests/classes/autoload_013.phpt
new file mode 100644
index 0000000..4309cea
--- /dev/null
+++ b/tests/classes/autoload_013.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Ensure the ReflectionClass constructor triggers autoload.
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ try {
+ new ReflectionClass("UndefC");
+ }
+ catch (ReflectionException $e) {
+ echo $e->getMessage();
+ }
+?>
+--EXPECTF--
+In autoload: string(6) "UndefC"
+Class UndefC does not exist
diff --git a/tests/classes/autoload_014.phpt b/tests/classes/autoload_014.phpt
new file mode 100644
index 0000000..a3f04b7
--- /dev/null
+++ b/tests/classes/autoload_014.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Ensure the ReflectionMethod constructor triggers autoload.
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ try {
+ new ReflectionMethod("UndefC::test");
+ }
+ catch (ReflectionException $e) {
+ echo $e->getMessage();
+ }
+?>
+--EXPECTF--
+In autoload: string(6) "UndefC"
+Class UndefC does not exist
diff --git a/tests/classes/autoload_015.phpt b/tests/classes/autoload_015.phpt
new file mode 100644
index 0000000..2b14a0d
--- /dev/null
+++ b/tests/classes/autoload_015.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Ensure the ReflectionProperty constructor triggers autoload.
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ try {
+ new ReflectionProperty('UndefC', 'p');
+ }
+ catch (ReflectionException $e) {
+ echo $e->getMessage();
+ }
+?>
+--EXPECTF--
+In autoload: string(6) "UndefC"
+Class UndefC does not exist
diff --git a/tests/classes/autoload_016.phpt b/tests/classes/autoload_016.phpt
new file mode 100644
index 0000000..60263ba
--- /dev/null
+++ b/tests/classes/autoload_016.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Ensure ReflectionClass::getProperty() triggers autoload
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ $rc = new ReflectionClass("stdClass");
+
+ try {
+ $rc->getProperty("UndefC::p");
+ } catch (ReflectionException $e) {
+ echo $e->getMessage();
+ }
+?>
+--EXPECTF--
+In autoload: string(6) "undefc"
+Class undefc does not exist
diff --git a/tests/classes/autoload_017.phpt b/tests/classes/autoload_017.phpt
new file mode 100644
index 0000000..26de9fd
--- /dev/null
+++ b/tests/classes/autoload_017.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Ensure ReflectionClass::implementsInterface triggers autoload.
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "In autoload: ";
+ var_dump($name);
+ }
+
+ $rc = new ReflectionClass("stdClass");
+
+ try {
+ $rc->implementsInterface("UndefI");
+ } catch (ReflectionException $e) {
+ echo $e->getMessage();
+ }
+?>
+--EXPECTF--
+In autoload: string(6) "UndefI"
+Interface UndefI does not exist \ No newline at end of file
diff --git a/tests/classes/autoload_018.phpt b/tests/classes/autoload_018.phpt
new file mode 100644
index 0000000..59e20e2
--- /dev/null
+++ b/tests/classes/autoload_018.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Ensure __autoload() allows for recursive calls if the class name differs.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "IN: " . __METHOD__ . "($name)\n";
+
+ static $i = 0;
+ if ($i++ > 10) {
+ echo "-> Recursion detected - as expected.\n";
+ return;
+ }
+
+ class_exists('UndefinedClass' . $i);
+
+ echo "OUT: " . __METHOD__ . "($name)\n";
+ }
+
+ var_dump(class_exists('UndefinedClass0'));
+?>
+--EXPECTF--
+IN: __autoload(UndefinedClass0)
+IN: __autoload(UndefinedClass1)
+IN: __autoload(UndefinedClass2)
+IN: __autoload(UndefinedClass3)
+IN: __autoload(UndefinedClass4)
+IN: __autoload(UndefinedClass5)
+IN: __autoload(UndefinedClass6)
+IN: __autoload(UndefinedClass7)
+IN: __autoload(UndefinedClass8)
+IN: __autoload(UndefinedClass9)
+IN: __autoload(UndefinedClass10)
+IN: __autoload(UndefinedClass11)
+-> Recursion detected - as expected.
+OUT: __autoload(UndefinedClass10)
+OUT: __autoload(UndefinedClass9)
+OUT: __autoload(UndefinedClass8)
+OUT: __autoload(UndefinedClass7)
+OUT: __autoload(UndefinedClass6)
+OUT: __autoload(UndefinedClass5)
+OUT: __autoload(UndefinedClass4)
+OUT: __autoload(UndefinedClass3)
+OUT: __autoload(UndefinedClass2)
+OUT: __autoload(UndefinedClass1)
+OUT: __autoload(UndefinedClass0)
+bool(false)
+
diff --git a/tests/classes/autoload_019.phpt b/tests/classes/autoload_019.phpt
new file mode 100644
index 0000000..7836320
--- /dev/null
+++ b/tests/classes/autoload_019.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Ensure __autoload() recursion is guarded for multiple lookups of same class using difference case.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo __FUNCTION__ . " $name\n";
+ class_exists("undefinedCLASS");
+ }
+
+ class_exists("unDefinedClass");
+?>
+--EXPECTF--
+__autoload unDefinedClass
diff --git a/tests/classes/autoload_020.phpt b/tests/classes/autoload_020.phpt
new file mode 100644
index 0000000..a88e561
--- /dev/null
+++ b/tests/classes/autoload_020.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Ensure __autoload() is triggered during unserialization.
+--FILE--
+<?php
+ function __autoload($name)
+ {
+ echo "in autoload: $name\n";
+ }
+
+ var_dump(unserialize('O:1:"C":0:{}'));
+?>
+--EXPECTF--
+in autoload: C
+object(__PHP_Incomplete_Class)#%d (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(1) "C"
+}
diff --git a/tests/classes/autoload_derived.p5c b/tests/classes/autoload_derived.p5c
new file mode 100755
index 0000000..93a4b35
--- /dev/null
+++ b/tests/classes/autoload_derived.p5c
@@ -0,0 +1,6 @@
+<?php
+
+class autoload_derived extends autoload_root {
+}
+
+?> \ No newline at end of file
diff --git a/tests/classes/autoload_implements.p5c b/tests/classes/autoload_implements.p5c
new file mode 100755
index 0000000..2c3479c
--- /dev/null
+++ b/tests/classes/autoload_implements.p5c
@@ -0,0 +1,10 @@
+<?php
+
+class autoload_implements implements autoload_interface {
+ function testFunction()
+ {
+ return true;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/classes/autoload_interface.p5c b/tests/classes/autoload_interface.p5c
new file mode 100755
index 0000000..6908155
--- /dev/null
+++ b/tests/classes/autoload_interface.p5c
@@ -0,0 +1,7 @@
+<?php
+
+interface autoload_interface {
+ function testFunction();
+}
+
+?> \ No newline at end of file
diff --git a/tests/classes/autoload_root.p5c b/tests/classes/autoload_root.p5c
new file mode 100755
index 0000000..9559d36
--- /dev/null
+++ b/tests/classes/autoload_root.p5c
@@ -0,0 +1,10 @@
+<?php
+
+class autoload_root {
+ function testFunction()
+ {
+ return true;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/classes/bug23951.phpt b/tests/classes/bug23951.phpt
new file mode 100644
index 0000000..2e272b8
--- /dev/null
+++ b/tests/classes/bug23951.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Bug #23951 (Defines not working in inherited classes)
+--FILE--
+<?php
+
+define('FOO1', 1);
+define('FOO2', 2);
+
+class A {
+
+ public $a_var = array(FOO1=>'foo1_value', FOO2=>'foo2_value');
+
+}
+
+class B extends A {
+
+ public $b_var = 'foo';
+
+}
+
+$a = new A;
+$b = new B;
+
+print_r($a);
+print_r($b->a_var);
+print_r($b->b_var);
+
+?>
+--EXPECT--
+A Object
+(
+ [a_var] => Array
+ (
+ [1] => foo1_value
+ [2] => foo2_value
+ )
+
+)
+Array
+(
+ [1] => foo1_value
+ [2] => foo2_value
+)
+foo
diff --git a/tests/classes/bug24399.phpt b/tests/classes/bug24399.phpt
new file mode 100644
index 0000000..fedf8e5
--- /dev/null
+++ b/tests/classes/bug24399.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #24399 (is_subclass_of() crashes when parent class doesn't exist)
+--FILE--
+<?php
+class dooh {
+ public $blah;
+}
+$d = new dooh;
+var_dump(is_subclass_of($d, 'dooh'));
+?>
+--EXPECT--
+bool(false)
diff --git a/tests/classes/bug24445.phpt b/tests/classes/bug24445.phpt
new file mode 100644
index 0000000..af08307
--- /dev/null
+++ b/tests/classes/bug24445.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Bug #24445 (get_parent_class() returns the current class when passed an object)
+--FILE--
+<?php
+class Test { }
+var_dump(get_parent_class('Test'));
+$t = new Test;
+var_dump(get_parent_class($t));
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/tests/classes/bug26737.phpt b/tests/classes/bug26737.phpt
new file mode 100644
index 0000000..e190318
--- /dev/null
+++ b/tests/classes/bug26737.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #26737 (Protected and private variables are not saved on serialization when a user defined __sleep is used)
+--FILE--
+<?php
+class foo
+{
+ private $private = 'private';
+ protected $protected = 'protected';
+ public $public = 'public';
+
+ public function __sleep()
+ {
+ return array('private', 'protected', 'public', 'no_such');
+ }
+}
+$foo = new foo();
+$data = serialize($foo);
+var_dump(str_replace("\0", '\0', $data));
+?>
+--EXPECTF--
+Notice: serialize(): "no_such" returned as member variable from __sleep() but does not exist in %s on line %d
+string(130) "O:3:"foo":4:{s:12:"\0foo\0private";s:7:"private";s:12:"\0*\0protected";s:9:"protected";s:6:"public";s:6:"public";s:7:"no_such";N;}"
diff --git a/tests/classes/bug27468.phpt b/tests/classes/bug27468.phpt
new file mode 100644
index 0000000..58a7b6c
--- /dev/null
+++ b/tests/classes/bug27468.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #27468 (foreach in __destruct() causes segfault)
+--FILE--
+<?php
+class foo {
+ function __destruct() {
+ foreach ($this->x as $x);
+ }
+}
+new foo();
+echo 'OK';
+?>
+--EXPECTF--
+Notice: Undefined property: foo::$x in %sbug27468.php on line 4
+
+Warning: Invalid argument supplied for foreach() in %sbug27468.php on line 4
+OK
diff --git a/tests/classes/bug27504.phpt b/tests/classes/bug27504.phpt
new file mode 100644
index 0000000..5f2c5a0
--- /dev/null
+++ b/tests/classes/bug27504.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #27504 (call_user_func_array allows calling of private/protected methods)
+--FILE--
+<?php
+ class foo {
+ function __construct () {
+ $this->bar('1');
+ }
+ private function bar ( $param ) {
+ echo 'Called function foo:bar('.$param.')'."\n";
+ }
+ }
+
+ $foo = new foo();
+
+ call_user_func_array( array( $foo , 'bar' ) , array( '2' ) );
+
+ $foo->bar('3');
+?>
+--EXPECTF--
+Called function foo:bar(1)
+
+Warning: call_user_func_array() expects parameter 1 to be a valid callback, cannot access private method foo::bar() in %s on line %d
+
+Fatal error: Call to private method foo::bar() from context '' in %s on line %d
diff --git a/tests/classes/bug29446.phpt b/tests/classes/bug29446.phpt
new file mode 100644
index 0000000..5e30e8e
--- /dev/null
+++ b/tests/classes/bug29446.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #29446 (ZE allows multiple declarations of the same class constant)
+--FILE--
+<?php
+
+class testClass {
+ const TEST_CONST = 'test';
+ const TEST_CONST = 'test1';
+
+ function testClass() {
+ echo self::TEST_CONST;
+ }
+}
+
+$test = new testClass;
+
+?>
+--EXPECTF--
+Fatal error: Cannot redefine class constant testClass::TEST_CONST in %s on line 5 \ No newline at end of file
diff --git a/tests/classes/bug63462.phpt b/tests/classes/bug63462.phpt
new file mode 100644
index 0000000..dc5edbd
--- /dev/null
+++ b/tests/classes/bug63462.phpt
@@ -0,0 +1,71 @@
+--TEST--
+Test script to verify that magic methods should be called only once when accessing an unset property.
+--CREDITS--
+Marco Pivetta <ocramius@gmail.com>
+--XFAIL--
+Bug 63462 is not yet fixed
+--FILE--
+<?php
+class Test {
+ public $publicProperty;
+ protected $protectedProperty;
+ private $privateProperty;
+
+ public function __construct() {
+ unset(
+ $this->publicProperty,
+ $this->protectedProperty,
+ $this->privateProperty
+ );
+ }
+
+ function __get($name) {
+ echo '__get ' . $name . "\n";
+ return $this->$name;
+ }
+
+ function __set($name, $value) {
+ echo '__set ' . $name . "\n";
+ $this->$name = $value;
+ }
+
+ function __isset($name) {
+ echo '__isset ' . $name . "\n";
+ return isset($this->$name);
+ }
+}
+
+$test = new Test();
+
+$test->nonExisting;
+$test->publicProperty;
+$test->protectedProperty;
+$test->privateProperty;
+isset($test->nonExisting);
+isset($test->publicProperty);
+isset($test->protectedProperty);
+isset($test->privateProperty);
+$test->nonExisting = 'value';
+$test->publicProperty = 'value';
+$test->protectedProperty = 'value';
+$test->privateProperty = 'value';
+
+?>
+
+--EXPECTF--
+__get nonExisting
+Notice: Undefined index: nonExisting in %__set__get_006.php on line %d
+__get publicProperty
+Notice: Undefined index: publicProperty in %__set__get_006.php on line %d
+__get protectedProperty
+Notice: Undefined index: protectedProperty in %__set__get_006.php on line %d
+__get privateProperty
+Notice: Undefined index: privateProperty in %__set__get_006.php on line %d
+__isset nonExisting
+__isset publicProperty
+__isset protectedProperty
+__isset privateProperty
+__set nonExisting
+__set publicProperty
+__set protectedProperty
+__set privateProperty
diff --git a/tests/classes/class_abstract.phpt b/tests/classes/class_abstract.phpt
new file mode 100644
index 0000000..880f849
--- /dev/null
+++ b/tests/classes/class_abstract.phpt
@@ -0,0 +1,28 @@
+--TEST--
+ZE2 An abstract class cannot be instanciated
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+abstract class base {
+ function show() {
+ echo "base\n";
+ }
+}
+
+class derived extends base {
+}
+
+$t = new derived();
+$t->show();
+
+$t = new base();
+$t->show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+base
+
+Fatal error: Cannot instantiate abstract class base in %s on line %d
diff --git a/tests/classes/class_example.phpt b/tests/classes/class_example.phpt
new file mode 100644
index 0000000..621958b
--- /dev/null
+++ b/tests/classes/class_example.phpt
@@ -0,0 +1,85 @@
+--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 */
+}
+
+$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
diff --git a/tests/classes/class_final.phpt b/tests/classes/class_final.phpt
new file mode 100644
index 0000000..5c73cb2
--- /dev/null
+++ b/tests/classes/class_final.phpt
@@ -0,0 +1,22 @@
+--TEST--
+ZE2 A final class cannot be inherited
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+final class base {
+ function show() {
+ echo "base\n";
+ }
+}
+
+$t = new base();
+
+class derived extends base {
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Class derived may not inherit from final class (base) in %s on line %d
diff --git a/tests/classes/class_stdclass.phpt b/tests/classes/class_stdclass.phpt
new file mode 100644
index 0000000..5e3422a
--- /dev/null
+++ b/tests/classes/class_stdclass.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Instantiate stdClass
+--FILE--
+<?php
+
+$obj = new stdClass;
+
+echo get_class($obj)."\n";
+
+echo "Done\n";
+?>
+--EXPECTF--
+stdClass
+Done
diff --git a/tests/classes/clone_001.phpt b/tests/classes/clone_001.phpt
new file mode 100644
index 0000000..eb06c1f
--- /dev/null
+++ b/tests/classes/clone_001.phpt
@@ -0,0 +1,43 @@
+--TEST--
+ZE2 object cloning, 1
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+ public $p1 = 1;
+ public $p2 = 2;
+ public $p3;
+};
+
+$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
diff --git a/tests/classes/clone_002.phpt b/tests/classes/clone_002.phpt
new file mode 100644
index 0000000..4430a2c
--- /dev/null
+++ b/tests/classes/clone_002.phpt
@@ -0,0 +1,45 @@
+--TEST--
+ZE2 object cloning, 2
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+ public $p1 = 1;
+ public $p2 = 2;
+ public $p3;
+ public function __clone() {
+ }
+};
+
+$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
diff --git a/tests/classes/clone_003.phpt b/tests/classes/clone_003.phpt
new file mode 100644
index 0000000..9a251c5
--- /dev/null
+++ b/tests/classes/clone_003.phpt
@@ -0,0 +1,58 @@
+--TEST--
+ZE2 object cloning, 3
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--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';
+ }
+}
+
+$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
+ [p3] => test:3
+ [p4] => A
+ [p5] => test:5
+ [p2] => base:2
+ [p6:base:private] => base:6
+)
+Clown
+test Object
+(
+ [p1] => test:1
+ [p3] => test:3
+ [p4] => A
+ [p5] => clone:5
+ [p2] => base:2
+ [p6:base:private] => base:6
+)
+Done
diff --git a/tests/classes/clone_004.phpt b/tests/classes/clone_004.phpt
new file mode 100644
index 0000000..2059103
--- /dev/null
+++ b/tests/classes/clone_004.phpt
@@ -0,0 +1,82 @@
+--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';
+
+ // reenable cloning
+ public function __clone() {}
+
+ public function show() {
+ var_dump($this);
+ }
+}
+
+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) {
+ ["b"]=>
+ array(2) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(4)
+ }
+ ["a"]=>
+ array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ }
+}
+Clone
+object(test)#2 (2) {
+ ["b"]=>
+ array(2) {
+ [0]=>
+ int(3)
+ [1]=>
+ int(4)
+ }
+ ["a"]=>
+ array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ }
+}
+Modify
+object(test)#2 (2) {
+ ["b"]=>
+ int(6)
+ ["a"]=>
+ int(5)
+}
+Done
diff --git a/tests/classes/clone_005.phpt b/tests/classes/clone_005.phpt
new file mode 100644
index 0000000..bfe4d66
--- /dev/null
+++ b/tests/classes/clone_005.phpt
@@ -0,0 +1,19 @@
+--TEST--
+ZE2 object cloning, 5
+--FILE--
+<?php
+abstract class base {
+ public $a = 'base';
+
+ // disallow cloning once forever
+ final private function __clone() {}
+}
+
+class test extends base {
+ // reenabling should fail
+ public function __clone() {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Cannot override final method base::__clone() in %sclone_005.php on line %d
diff --git a/tests/classes/clone_006.phpt b/tests/classes/clone_006.phpt
new file mode 100644
index 0000000..de22fec
--- /dev/null
+++ b/tests/classes/clone_006.phpt
@@ -0,0 +1,41 @@
+--TEST--
+ZE2 object cloning, 6
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--INI--
+error_reporting=2047
+--FILE--
+<?php
+
+class MyCloneable {
+ static $id = 0;
+
+ function MyCloneable() {
+ $this->id = self::$id++;
+ }
+
+ function __clone() {
+ $this->address = "New York";
+ $this->id = self::$id++;
+ }
+}
+
+$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";
+
+?>
+--EXPECT--
+0
+1
+Hello
+New York
diff --git a/tests/classes/constants_basic_001.phpt b/tests/classes/constants_basic_001.phpt
new file mode 100644
index 0000000..74b0fcd
--- /dev/null
+++ b/tests/classes/constants_basic_001.phpt
@@ -0,0 +1,89 @@
+--TEST--
+Class constant declarations
+--FILE--
+<?php
+ define('DEFINED', 1234);
+ $def = 456;
+ define('DEFINED_TO_VAR', $def);
+ define('DEFINED_TO_UNDEF_VAR', $undef);
+
+ class C
+ {
+ const c0 = UNDEFINED;
+
+ const c1 = 1, c2 = 1.5;
+ const c3 = + 1, c4 = + 1.5;
+ const c5 = -1, c6 = -1.5;
+
+ const c7 = __LINE__;
+ const c8 = __FILE__;
+ const c9 = __CLASS__;
+ const c10 = __METHOD__;
+ const c11 = __FUNCTION__;
+
+ const c12 = DEFINED;
+ const c13 = DEFINED_TO_VAR;
+ const c14 = DEFINED_TO_UNDEF_VAR;
+
+ const c15 = "hello1";
+ const c16 = 'hello2';
+ const c17 = C::c16;
+ const c18 = self::c17;
+ }
+
+ echo "\nAttempt to access various kinds of class constants:\n";
+ var_dump(C::c0);
+ var_dump(C::c1);
+ var_dump(C::c2);
+ var_dump(C::c3);
+ var_dump(C::c4);
+ var_dump(C::c5);
+ var_dump(C::c6);
+ var_dump(C::c7);
+ var_dump(C::c8);
+ var_dump(C::c9);
+ var_dump(C::c10);
+ var_dump(C::c11);
+ var_dump(C::c12);
+ var_dump(C::c13);
+ var_dump(C::c14);
+ var_dump(C::c15);
+ var_dump(C::c16);
+ var_dump(C::c17);
+ var_dump(C::c18);
+
+ echo "\nExpecting fatal error:\n";
+ var_dump(C::c19);
+
+ echo "\nYou should not see this.";
+?>
+--EXPECTF--
+
+Notice: Undefined variable: undef in %s on line 5
+
+Attempt to access various kinds of class constants:
+
+Notice: Use of undefined constant UNDEFINED - assumed 'UNDEFINED' in %s on line %d
+string(9) "UNDEFINED"
+int(1)
+float(1.5)
+int(1)
+float(1.5)
+int(-1)
+float(-1.5)
+int(15)
+string(%d) "%s"
+string(1) "C"
+string(1) "C"
+string(0) ""
+int(1234)
+int(456)
+NULL
+string(6) "hello1"
+string(6) "hello2"
+string(6) "hello2"
+string(6) "hello2"
+
+Expecting fatal error:
+
+Fatal error: Undefined class constant 'c19' in %s on line 53
diff --git a/tests/classes/constants_basic_002.phpt b/tests/classes/constants_basic_002.phpt
new file mode 100644
index 0000000..0e53ca9
--- /dev/null
+++ b/tests/classes/constants_basic_002.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Basic class support - defining and reading a class constant.
+--FILE--
+<?php
+ class aclass
+ {
+ const myConst = "hello";
+ }
+
+ echo "\nRead class constant.\n";
+ var_dump(aclass::myConst);
+
+ echo "\nFail to read class constant from instance.\n";
+ $myInstance = new aclass();
+ var_dump($myInstance->myConst);
+
+ echo "\nClass constant not visible in object var_dump.\n";
+ var_dump($myInstance)
+?>
+--EXPECTF--
+
+Read class constant.
+string(5) "hello"
+
+Fail to read class constant from instance.
+
+Notice: Undefined property: aclass::$myConst in %s on line 12
+NULL
+
+Class constant not visible in object var_dump.
+object(aclass)#%d (0) {
+}
diff --git a/tests/classes/constants_basic_003.inc b/tests/classes/constants_basic_003.inc
new file mode 100644
index 0000000..be193e6
--- /dev/null
+++ b/tests/classes/constants_basic_003.inc
@@ -0,0 +1,5 @@
+<?php
+class A {
+ const MY_CONST = "hello from A";
+}
+?> \ No newline at end of file
diff --git a/tests/classes/constants_basic_003.phpt b/tests/classes/constants_basic_003.phpt
new file mode 100644
index 0000000..052af85
--- /dev/null
+++ b/tests/classes/constants_basic_003.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Ensure class properties and constants can be defined in terms of constants that are not known at compile time.
+--FILE--
+<?php
+ include 'constants_basic_003.inc';
+ class B
+ {
+ public static $a = A::MY_CONST;
+ public static $c = C::MY_CONST;
+ const ca = A::MY_CONST;
+ const cc = C::MY_CONST;
+ }
+
+ class C
+ {
+ const MY_CONST = "hello from C";
+ }
+
+ var_dump(B::$a);
+ var_dump(B::$c);
+ var_dump(B::ca);
+ var_dump(B::cc);
+?>
+--EXPECTF--
+string(12) "hello from A"
+string(12) "hello from C"
+string(12) "hello from A"
+string(12) "hello from C"
diff --git a/tests/classes/constants_basic_004.phpt b/tests/classes/constants_basic_004.phpt
new file mode 100644
index 0000000..cade668
--- /dev/null
+++ b/tests/classes/constants_basic_004.phpt
@@ -0,0 +1,99 @@
+--TEST--
+Test properties with array default values using class constants as keys and values.
+--FILE--
+<?php
+ class X
+ {
+ // Static and instance array using class constants
+ public static $sa_x = array(B::KEY => B::VALUE);
+ public $a_x = array(B::KEY => B::VALUE);
+ }
+
+ class B
+ {
+ const KEY = "key";
+ const VALUE = "value";
+
+ // Static and instance array using class constants with self
+ public static $sa_b = array(self::KEY => self::VALUE);
+ public $a_b = array(self::KEY => self::VALUE);
+ }
+
+ class C extends B
+ {
+ // Static and instance array using class constants with parent
+ public static $sa_c_parent = array(parent::KEY => parent::VALUE);
+ public $a_c_parent = array(parent::KEY => parent::VALUE);
+
+ // Static and instance array using class constants with self (constants should be inherited)
+ public static $sa_c_self = array(self::KEY => self::VALUE);
+ public $a_c_self = array(self::KEY => self::VALUE);
+
+ // Should also include inherited properties from B.
+ }
+
+ echo "\nStatic properties:\n";
+ var_dump(X::$sa_x, B::$sa_b, C::$sa_b, C::$sa_c_parent, C::$sa_c_self);
+
+ echo "\nInstance properties:\n";
+ $x = new x;
+ $b = new B;
+ $c = new C;
+ var_dump($x, $b, $c);
+?>
+--EXPECTF--
+
+Static properties:
+array(1) {
+ ["key"]=>
+ string(5) "value"
+}
+array(1) {
+ ["key"]=>
+ string(5) "value"
+}
+array(1) {
+ ["key"]=>
+ string(5) "value"
+}
+array(1) {
+ ["key"]=>
+ string(5) "value"
+}
+array(1) {
+ ["key"]=>
+ string(5) "value"
+}
+
+Instance properties:
+object(X)#%d (1) {
+ ["a_x"]=>
+ array(1) {
+ ["key"]=>
+ string(5) "value"
+ }
+}
+object(B)#%d (1) {
+ ["a_b"]=>
+ array(1) {
+ ["key"]=>
+ string(5) "value"
+ }
+}
+object(C)#%d (3) {
+ ["a_c_parent"]=>
+ array(1) {
+ ["key"]=>
+ string(5) "value"
+ }
+ ["a_c_self"]=>
+ array(1) {
+ ["key"]=>
+ string(5) "value"
+ }
+ ["a_b"]=>
+ array(1) {
+ ["key"]=>
+ string(5) "value"
+ }
+}
diff --git a/tests/classes/constants_basic_005.phpt b/tests/classes/constants_basic_005.phpt
new file mode 100644
index 0000000..c840f53
--- /dev/null
+++ b/tests/classes/constants_basic_005.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Test constants with default values based on other constants.
+--FILE--
+<?php
+ class C
+ {
+ const CONST_2 = self::CONST_1;
+ const CONST_1 = self::BASE_CONST;
+ const BASE_CONST = 'hello';
+ }
+ var_dump(C::CONST_1, C::CONST_2);
+?>
+--EXPECTF--
+string(5) "hello"
+string(5) "hello"
+
diff --git a/tests/classes/constants_basic_006.phpt b/tests/classes/constants_basic_006.phpt
new file mode 100644
index 0000000..73cf0ef
--- /dev/null
+++ b/tests/classes/constants_basic_006.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Ensure class constants are not evaluated when a class is looked up to resolve inheritance during runtime.
+--FILE--
+<?php
+ class C
+ {
+ const X = E::A;
+ public static $a = array(K => D::V, E::A => K);
+ }
+
+ eval('class D extends C { const V = \'test\'; }');
+
+ class E extends D
+ {
+ const A = "hello";
+ }
+
+ define('K', "nasty");
+
+ var_dump(C::X, C::$a, D::X, D::$a, E::X, E::$a);
+?>
+--EXPECTF--
+string(5) "hello"
+array(2) {
+ ["nasty"]=>
+ string(4) "test"
+ ["hello"]=>
+ string(5) "nasty"
+}
+string(5) "hello"
+array(2) {
+ ["nasty"]=>
+ string(4) "test"
+ ["hello"]=>
+ string(5) "nasty"
+}
+string(5) "hello"
+array(2) {
+ ["nasty"]=>
+ string(4) "test"
+ ["hello"]=>
+ string(5) "nasty"
+}
diff --git a/tests/classes/constants_error_001.phpt b/tests/classes/constants_error_001.phpt
new file mode 100644
index 0000000..9bb5533
--- /dev/null
+++ b/tests/classes/constants_error_001.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Error case: duplicate class constant definition
+--FILE--
+<?php
+ class myclass
+ {
+ const myConst = "hello";
+ const myConst = "hello again";
+ }
+?>
+--EXPECTF--
+
+Fatal error: Cannot redefine class constant myclass::myConst in %s on line 5
diff --git a/tests/classes/constants_error_002.phpt b/tests/classes/constants_error_002.phpt
new file mode 100644
index 0000000..be27971
--- /dev/null
+++ b/tests/classes/constants_error_002.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Error case: class constant as an array
+--FILE--
+<?php
+ class myclass
+ {
+ const myConst = array();
+ }
+?>
+--EXPECTF--
+
+Fatal error: Arrays are not allowed in class constants in %s on line 4
diff --git a/tests/classes/constants_error_003.phpt b/tests/classes/constants_error_003.phpt
new file mode 100644
index 0000000..c67768c
--- /dev/null
+++ b/tests/classes/constants_error_003.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Basic class support - attempting to pass a class constant by reference.
+--FILE--
+<?php
+ class aclass
+ {
+ const myConst = "hello";
+ }
+
+ function f(&$a)
+ {
+ $a = "changed";
+ }
+
+ f(aclass::myConst);
+ var_dump(aclass::myConst);
+?>
+--EXPECTF--
+
+Fatal error: Only variables can be passed by reference in %s on line 12
diff --git a/tests/classes/constants_error_004.phpt b/tests/classes/constants_error_004.phpt
new file mode 100644
index 0000000..03e6725
--- /dev/null
+++ b/tests/classes/constants_error_004.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Class constant whose initial value refereces a non-existent class
+--FILE--
+<?php
+ class C
+ {
+ const c1 = D::hello;
+ }
+
+ $a = new C();
+?>
+--EXPECTF--
+Fatal error: Class 'D' not found in %s on line %d
diff --git a/tests/classes/constants_error_005.phpt b/tests/classes/constants_error_005.phpt
new file mode 100644
index 0000000..1283783
--- /dev/null
+++ b/tests/classes/constants_error_005.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Error case: class constant as an encapsed containing a variable
+--FILE--
+<?php
+ class myclass
+ {
+ const myConst = "$myVar";
+ }
+?>
+--EXPECTF--
+
+Parse error: %s in %s on line %d
diff --git a/tests/classes/constants_error_006.phpt b/tests/classes/constants_error_006.phpt
new file mode 100644
index 0000000..f3f14b8
--- /dev/null
+++ b/tests/classes/constants_error_006.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Basic class support - attempting to modify a class constant by assignment
+--FILE--
+<?php
+ class aclass
+ {
+ const myConst = "hello";
+ }
+
+ echo "\nTrying to modify a class constant directly - should be parse error.\n";
+ aclass::myConst = "no!!";
+ var_dump(aclass::myConst);
+?>
+--EXPECTF--
+
+Parse error: %s in %s on line %d
diff --git a/tests/classes/constants_error_007.phpt b/tests/classes/constants_error_007.phpt
new file mode 100644
index 0000000..4be8d88
--- /dev/null
+++ b/tests/classes/constants_error_007.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Basic class support - attempting to create a reference to a class constant
+--FILE--
+<?php
+ class aclass
+ {
+ const myConst = "hello";
+ }
+
+ echo "\nAttempting to create a reference to a class constant - should be parse error.\n";
+ $a = &aclass::myConst;
+?>
+--EXPECTF--
+
+Parse error: %s in %s on line %d
diff --git a/tests/classes/constants_scope_001.phpt b/tests/classes/constants_scope_001.phpt
new file mode 100644
index 0000000..5006628
--- /dev/null
+++ b/tests/classes/constants_scope_001.phpt
@@ -0,0 +1,38 @@
+--TEST--
+ZE2 class constants and scope
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class ErrorCodes {
+ const FATAL = "Fatal error\n";
+ const WARNING = "Warning\n";
+ const INFO = "Informational message\n";
+
+ static function print_fatal_error_codes() {
+ echo "FATAL = " . FATAL . "\n";
+ echo "self::FATAL = " . self::FATAL;
+ }
+}
+
+class ErrorCodesDerived extends ErrorCodes {
+ const FATAL = "Worst error\n";
+ static function print_fatal_error_codes() {
+ echo "self::FATAL = " . self::FATAL;
+ echo "parent::FATAL = " . parent::FATAL;
+ }
+}
+
+/* Call the static function and move into the ErrorCodes scope */
+ErrorCodes::print_fatal_error_codes();
+ErrorCodesDerived::print_fatal_error_codes();
+
+?>
+--EXPECTF--
+
+Notice: Use of undefined constant FATAL - assumed 'FATAL' in %sconstants_scope_001.php on line %d
+FATAL = FATAL
+self::FATAL = Fatal error
+self::FATAL = Worst error
+parent::FATAL = Fatal error
diff --git a/tests/classes/ctor_dtor.phpt b/tests/classes/ctor_dtor.phpt
new file mode 100644
index 0000000..ea6813c
--- /dev/null
+++ b/tests/classes/ctor_dtor.phpt
@@ -0,0 +1,40 @@
+--TEST--
+ZE2 The new constructor/destructor is called
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class early {
+ function early() {
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ }
+ function __destruct() {
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ }
+}
+
+class late {
+ function __construct() {
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ }
+ function __destruct() {
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ }
+}
+
+$t = new early();
+$t->early();
+unset($t);
+$t = new late();
+//unset($t); delay to end of script
+
+echo "Done\n";
+?>
+--EXPECTF--
+early::early
+early::early
+early::__destruct
+late::__construct
+Done
+late::__destruct
diff --git a/tests/classes/ctor_dtor_inheritance.phpt b/tests/classes/ctor_dtor_inheritance.phpt
new file mode 100644
index 0000000..8ae2a5d
--- /dev/null
+++ b/tests/classes/ctor_dtor_inheritance.phpt
@@ -0,0 +1,99 @@
+--TEST--
+ZE2 A derived class can use the inherited constructor/destructor
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+// This test checks for:
+// - inherited constructors/destructors are not called automatically
+// - base classes know about derived properties in constructor/destructor
+// - base class constructors/destructors know the instanciated class name
+
+class base {
+ public $name;
+
+ function __construct() {
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ $this->name = 'base';
+ print_r($this);
+ }
+
+ function __destruct() {
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ print_r($this);
+ }
+}
+
+class derived extends base {
+ public $other;
+
+ function __construct() {
+ $this->name = 'init';
+ $this->other = 'other';
+ print_r($this);
+ parent::__construct();
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ $this->name = 'derived';
+ print_r($this);
+ }
+
+ function __destruct() {
+ parent::__destruct();
+ echo __CLASS__ . "::" . __FUNCTION__ . "\n";
+ print_r($this);
+ }
+}
+
+echo "Testing class base\n";
+$t = new base();
+unset($t);
+echo "Testing class derived\n";
+$t = new derived();
+unset($t);
+
+echo "Done\n";
+?>
+--EXPECTF--
+Testing class base
+base::__construct
+base Object
+(
+ [name] => base
+)
+base::__destruct
+base Object
+(
+ [name] => base
+)
+Testing class derived
+derived Object
+(
+ [other] => other
+ [name] => init
+)
+base::__construct
+derived Object
+(
+ [other] => other
+ [name] => base
+)
+derived::__construct
+derived Object
+(
+ [other] => other
+ [name] => derived
+)
+base::__destruct
+derived Object
+(
+ [other] => other
+ [name] => derived
+)
+derived::__destruct
+derived Object
+(
+ [other] => other
+ [name] => derived
+)
+Done
diff --git a/tests/classes/ctor_failure.phpt b/tests/classes/ctor_failure.phpt
new file mode 100644
index 0000000..b7d3b64
--- /dev/null
+++ b/tests/classes/ctor_failure.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 Do not call destructors if constructor fails
+--FILE--
+<?php
+
+class Test
+{
+ function __construct($msg) {
+ echo __METHOD__ . "($msg)\n";
+ throw new Exception($msg);
+ }
+
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+try
+{
+ $o = new Test('Hello');
+ unset($o);
+}
+catch (Exception $e)
+{
+ echo 'Caught ' . get_class($e) . '(' . $e->getMessage() . ")\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+Test::__construct(Hello)
+Caught Exception(Hello)
+===DONE===
diff --git a/tests/classes/ctor_in_interface_01.phpt b/tests/classes/ctor_in_interface_01.phpt
new file mode 100644
index 0000000..e5ad30e
--- /dev/null
+++ b/tests/classes/ctor_in_interface_01.phpt
@@ -0,0 +1,19 @@
+--TEST--
+ZE2 A class constructor must keep the signature of an interface
+--FILE--
+<?php
+interface constr
+{
+ function __construct();
+}
+
+class implem implements constr
+{
+ function __construct($a)
+ {
+ }
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of implem::__construct() must be compatible with constr::__construct() in %s on line %d
diff --git a/tests/classes/ctor_in_interface_02.phpt b/tests/classes/ctor_in_interface_02.phpt
new file mode 100644
index 0000000..08e6f36
--- /dev/null
+++ b/tests/classes/ctor_in_interface_02.phpt
@@ -0,0 +1,34 @@
+--TEST--
+ZE2 A class constructor must keep the signature of all interfaces
+--FILE--
+<?php
+interface constr1
+{
+ function __construct();
+}
+
+interface constr2 extends constr1
+{
+}
+
+class implem12 implements constr2
+{
+ function __construct()
+ {
+ }
+}
+
+interface constr3
+{
+ function __construct($a);
+}
+
+class implem13 implements constr1, constr3
+{
+ function __construct()
+ {
+ }
+}
+?>
+--EXPECTF--
+Fatal error: Declaration of implem13::__construct() must be compatible with constr3::__construct($a) in %s on line %d
diff --git a/tests/classes/ctor_in_interface_03.phpt b/tests/classes/ctor_in_interface_03.phpt
new file mode 100644
index 0000000..ac73331
--- /dev/null
+++ b/tests/classes/ctor_in_interface_03.phpt
@@ -0,0 +1,23 @@
+--TEST--
+ZE2 A class constructor must keep the signature of base class interfaces
+--FILE--
+<?php
+interface constr
+{
+ function __construct();
+}
+
+abstract class implem implements constr
+{
+}
+
+class derived extends implem
+{
+ function __construct($a)
+ {
+ }
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of derived::__construct() must be compatible with constr::__construct() in %s on line %d
diff --git a/tests/classes/ctor_in_interface_04.phpt b/tests/classes/ctor_in_interface_04.phpt
new file mode 100644
index 0000000..94be655
--- /dev/null
+++ b/tests/classes/ctor_in_interface_04.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 A class constructor must keep the signature of base class interfaces
+--FILE--
+<?php
+interface constr
+{
+ function __construct();
+}
+
+class implem implements constr
+{
+ function __construct()
+ {
+ }
+}
+
+class derived extends implem
+{
+ function __construct($a)
+ {
+ }
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of derived::__construct() must be compatible with constr::__construct() in %s on line %d
diff --git a/tests/classes/ctor_name_clash.phpt b/tests/classes/ctor_name_clash.phpt
new file mode 100644
index 0000000..1a1d6fa
--- /dev/null
+++ b/tests/classes/ctor_name_clash.phpt
@@ -0,0 +1,22 @@
+--TEST--
+ZE2 The child class can re-use the parent class name for a function member
+--FILE--
+<?php
+class base {
+ function base() {
+ echo __CLASS__."::".__FUNCTION__."\n";
+ }
+}
+
+class derived extends base {
+ function base() {
+ echo __CLASS__."::".__FUNCTION__."\n";
+ }
+}
+
+$obj = new derived();
+$obj->base();
+?>
+--EXPECTF--
+base::base
+derived::base
diff --git a/tests/classes/ctor_visibility.phpt b/tests/classes/ctor_visibility.phpt
new file mode 100644
index 0000000..8d3b1c5
--- /dev/null
+++ b/tests/classes/ctor_visibility.phpt
@@ -0,0 +1,69 @@
+--TEST--
+ZE2 A private constructor cannot be called
+--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;
+ }
+}
+
+Derived::f();
+
+class TestPriv
+{
+ private function __construct()
+ {
+ echo __METHOD__ . "()\n";
+ }
+
+ static function f()
+ {
+ new TestPriv;
+ }
+}
+
+TestPriv::f();
+
+class DerivedPriv extends TestPriv
+{
+ function __construct()
+ {
+ echo __METHOD__ . "()\n";
+ parent::__construct();
+ }
+
+ static function f()
+ {
+ new DerivedPriv;
+ }
+}
+
+DerivedPriv::f();
+
+?>
+===DONE===
+--EXPECTF--
+Derived::__construct()
+Test::__construct()
+TestPriv::__construct()
+DerivedPriv::__construct()
+
+Fatal error: Cannot call private TestPriv::__construct() in %sctor_visibility.php on line %d
diff --git a/tests/classes/dereferencing_001.phpt b/tests/classes/dereferencing_001.phpt
new file mode 100644
index 0000000..dd2aba7
--- /dev/null
+++ b/tests/classes/dereferencing_001.phpt
@@ -0,0 +1,35 @@
+--TEST--
+ZE2 dereferencing of objects from methods
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Name {
+ function Name($_name) {
+ $this->name = $_name;
+ }
+
+ function display() {
+ echo $this->name . "\n";
+ }
+}
+
+class Person {
+ private $name;
+
+ function person($_name, $_address) {
+ $this->name = new Name($_name);
+ }
+
+ function getName() {
+ return $this->name;
+ }
+}
+
+$person = new Person("John", "New York");
+$person->getName()->display();
+
+?>
+--EXPECT--
+John
diff --git a/tests/classes/destructor_and_echo.phpt b/tests/classes/destructor_and_echo.phpt
new file mode 100644
index 0000000..0a25359
--- /dev/null
+++ b/tests/classes/destructor_and_echo.phpt
@@ -0,0 +1,24 @@
+--TEST--
+ZE2 Destructors and echo
+--FILE--
+<?php
+
+class Test
+{
+ function __construct() {
+ echo __METHOD__ . "\n";
+ }
+
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+$o = new Test;
+
+?>
+===DONE===
+--EXPECT--
+Test::__construct
+===DONE===
+Test::__destruct
diff --git a/tests/classes/destructor_and_exceptions.phpt b/tests/classes/destructor_and_exceptions.phpt
new file mode 100644
index 0000000..8100c92
--- /dev/null
+++ b/tests/classes/destructor_and_exceptions.phpt
@@ -0,0 +1,60 @@
+--TEST--
+ZE2 catch exception thrown in destructor
+--FILE--
+<?php
+
+class FailClass
+{
+ public $fatal;
+
+ function __destruct()
+ {
+ echo __METHOD__ . "\n";
+ throw new exception("FailClass");
+ echo "Done: " . __METHOD__ . "\n";
+ }
+}
+
+try
+{
+ $a = new FailClass;
+ unset($a);
+}
+catch(Exception $e)
+{
+ echo "Caught: " . $e->getMessage() . "\n";
+}
+
+class FatalException extends Exception
+{
+ function __construct($what)
+ {
+ echo __METHOD__ . "\n";
+ $o = new FailClass;
+ unset($o);
+ echo "Done: " . __METHOD__ . "\n";
+ }
+}
+
+try
+{
+ throw new FatalException("Damn");
+}
+catch(Exception $e)
+{
+ echo "Caught Exception: " . $e->getMessage() . "\n";
+}
+catch(FatalException $e)
+{
+ echo "Caught FatalException: " . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+FailClass::__destruct
+Caught: FailClass
+FatalException::__construct
+FailClass::__destruct
+Caught Exception: FailClass
+===DONE===
diff --git a/tests/classes/destructor_and_globals.phpt b/tests/classes/destructor_and_globals.phpt
new file mode 100644
index 0000000..9caf0f1
--- /dev/null
+++ b/tests/classes/destructor_and_globals.phpt
@@ -0,0 +1,56 @@
+--TEST--
+ZE2 accessing globals from destructor in shutdown
+--FILE--
+<?php
+$test_cnt = 0;
+$test_num = 0;
+
+function Show() {
+ global $test_cnt;
+ echo "Count: $test_cnt\n";
+}
+
+class counter {
+ protected $id;
+
+ public function __construct() {
+ global $test_cnt, $test_num;
+ $test_cnt++;
+ $this->id = $test_num++;
+ }
+
+ public function Show() {
+ echo 'Id: '.$this->id."\n";
+ }
+
+ // try protected here
+ public function __destruct() {
+ global $test_cnt;
+ $test_cnt--;
+ }
+
+ static public function destroy(&$obj) {
+ $obj = NULL;
+ }
+}
+Show();
+$obj1 = new counter;
+$obj1->Show();
+Show();
+$obj2 = new counter;
+$obj2->Show();
+Show();
+counter::destroy($obj1);
+Show();
+// or uncomment this line and it works
+//counter::destroy($obj2);
+echo "Done\n";
+?>
+--EXPECT--
+Count: 0
+Id: 0
+Count: 1
+Id: 1
+Count: 2
+Count: 1
+Done
diff --git a/tests/classes/destructor_and_references.phpt b/tests/classes/destructor_and_references.phpt
new file mode 100644
index 0000000..6b9b019
--- /dev/null
+++ b/tests/classes/destructor_and_references.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 Destructing and references
+--FILE--
+<?php
+
+class test1 {public $x;};
+class test2 {public $x;};
+class test3 {public $x;};
+class test4 {public $x;};
+
+$o1 = new test1;
+$o2 = new test2;
+$o3 = new test3;
+$o4 = new test4;
+
+$o3->x = &$o4;
+
+$r1 = &$o1;
+
+class once {}
+
+$o = new once;
+echo "Done\n";
+?>
+--EXPECT--
+Done
diff --git a/tests/classes/destructor_inheritance.phpt b/tests/classes/destructor_inheritance.phpt
new file mode 100644
index 0000000..b9a4665
--- /dev/null
+++ b/tests/classes/destructor_inheritance.phpt
@@ -0,0 +1,29 @@
+--TEST--
+ZE2 The inherited destructor is called
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class base {
+ function __construct() {
+ echo __METHOD__ . "\n";
+ }
+
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+class derived extends base {
+}
+
+$obj = new derived;
+
+unset($obj);
+
+echo 'Done';
+?>
+--EXPECT--
+base::__construct
+base::__destruct
+Done \ No newline at end of file
diff --git a/tests/classes/destructor_visibility_001.phpt b/tests/classes/destructor_visibility_001.phpt
new file mode 100644
index 0000000..7674c51
--- /dev/null
+++ b/tests/classes/destructor_visibility_001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+ZE2 Ensuring destructor visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Base {
+ private function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+class Derived extends Base {
+}
+
+$obj = new Derived;
+
+unset($obj);
+
+?>
+===DONE===
+--EXPECTF--
+Fatal error: Call to private Derived::__destruct() from context '' in %sdestructor_visibility_001.php on line %d
diff --git a/tests/classes/destructor_visibility_002.phpt b/tests/classes/destructor_visibility_002.phpt
new file mode 100644
index 0000000..2cc8333
--- /dev/null
+++ b/tests/classes/destructor_visibility_002.phpt
@@ -0,0 +1,24 @@
+--TEST--
+ZE2 Ensuring destructor visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Base {
+ private function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+class Derived extends Base {
+}
+
+$obj = new Derived;
+
+?>
+===DONE===
+--EXPECTF--
+===DONE===
+
+Warning: Call to private Derived::__destruct() from context '' during shutdown ignored in Unknown on line %d
diff --git a/tests/classes/destructor_visibility_003.phpt b/tests/classes/destructor_visibility_003.phpt
new file mode 100644
index 0000000..83e3efe
--- /dev/null
+++ b/tests/classes/destructor_visibility_003.phpt
@@ -0,0 +1,28 @@
+--TEST--
+ZE2 Ensuring destructor visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Base {
+ private function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+class Derived extends Base {
+ public function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+$obj = new Derived;
+
+unset($obj); // Derived::__destruct is being called not Base::__destruct
+
+?>
+===DONE===
+--EXPECTF--
+Derived::__destruct
+===DONE===
diff --git a/tests/classes/factory_001.phpt b/tests/classes/factory_001.phpt
new file mode 100644
index 0000000..97b69c1
--- /dev/null
+++ b/tests/classes/factory_001.phpt
@@ -0,0 +1,35 @@
+--TEST--
+ZE2 factory objects
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Circle {
+ function draw() {
+ echo "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();
+
+?>
+--EXPECT--
+Circle
+Square
diff --git a/tests/classes/factory_and_singleton_001.phpt b/tests/classes/factory_and_singleton_001.phpt
new file mode 100644
index 0000000..70fa020
--- /dev/null
+++ b/tests/classes/factory_and_singleton_001.phpt
@@ -0,0 +1,101 @@
+--TEST--
+ZE2 factory and singleton, test 1
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+ protected $x;
+
+ static private $test = NULL;
+ static private $cnt = 0;
+
+ static function factory($x) {
+ if (test::$test) {
+ return test::$test;
+ } else {
+ test::$test = new test($x);
+ return test::$test;
+ }
+ }
+
+ protected function __construct($x) {
+ test::$cnt++;
+ $this->x = $x;
+ }
+
+ static function destroy() {
+ test::$test = NULL;
+ }
+
+ protected function __destruct() {
+ test::$cnt--;
+ }
+
+ public function get() {
+ return $this->x;
+ }
+
+ static public function getX() {
+ if (test::$test) {
+ return test::$test->x;
+ } else {
+ return NULL;
+ }
+ }
+
+ static public function count() {
+ return test::$cnt;
+ }
+}
+
+echo "Access static members\n";
+var_dump(test::getX());
+var_dump(test::count());
+
+echo "Create x and y\n";
+$x = test::factory(1);
+$y = test::factory(2);
+var_dump(test::getX());
+var_dump(test::count());
+var_dump($x->get());
+var_dump($y->get());
+
+echo "Destruct x\n";
+$x = NULL;
+var_dump(test::getX());
+var_dump(test::count());
+var_dump($y->get());
+
+echo "Destruct y\n";
+$y = NULL;
+var_dump(test::getX());
+var_dump(test::count());
+
+echo "Destruct static\n";
+test::destroy();
+var_dump(test::getX());
+var_dump(test::count());
+
+echo "Done\n";
+?>
+--EXPECT--
+Access static members
+NULL
+int(0)
+Create x and y
+int(1)
+int(1)
+int(1)
+int(1)
+Destruct x
+int(1)
+int(1)
+int(1)
+Destruct y
+int(1)
+int(1)
+Destruct static
+NULL
+int(0)
+Done
diff --git a/tests/classes/factory_and_singleton_002.phpt b/tests/classes/factory_and_singleton_002.phpt
new file mode 100644
index 0000000..3308a56
--- /dev/null
+++ b/tests/classes/factory_and_singleton_002.phpt
@@ -0,0 +1,100 @@
+--TEST--
+ZE2 factory and singleton, test 2
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+ protected $x;
+
+ static private $test = NULL;
+ static private $cnt = 0;
+
+ static function factory($x) {
+ if (test::$test) {
+ return test::$test;
+ } else {
+ test::$test = new test($x);
+ return test::$test;
+ }
+ }
+
+ protected function __construct($x) {
+ test::$cnt++;
+ $this->x = $x;
+ }
+
+ static function destroy() {
+ test::$test = NULL;
+ }
+
+ protected function __destruct() {
+ test::$cnt--;
+ }
+
+ public function get() {
+ return $this->x;
+ }
+
+ static public function getX() {
+ if (test::$test) {
+ return test::$test->x;
+ } else {
+ return NULL;
+ }
+ }
+
+ static public function count() {
+ return test::$cnt;
+ }
+}
+
+echo "Access static members\n";
+var_dump(test::getX());
+var_dump(test::count());
+
+echo "Create x and y\n";
+$x = test::factory(1);
+$y = test::factory(2);
+var_dump(test::getX());
+var_dump(test::count());
+var_dump($x->get());
+var_dump($y->get());
+
+echo "Destruct x\n";
+$x = NULL;
+var_dump(test::getX());
+var_dump(test::count());
+var_dump($y->get());
+
+echo "Destruct y\n";
+$y = NULL;
+var_dump(test::getX());
+var_dump(test::count());
+
+//echo "Destruct static\n";
+//test::destroy();
+//var_dump(test::getX());
+//var_dump(test::count());
+
+echo "Done\n";
+?>
+--EXPECT--
+Access static members
+NULL
+int(0)
+Create x and y
+int(1)
+int(1)
+int(1)
+int(1)
+Destruct x
+int(1)
+int(1)
+int(1)
+Destruct y
+int(1)
+int(1)
+Done
+
+Warning: Call to protected test::__destruct() from context '' during shutdown ignored in Unknown on line 0
diff --git a/tests/classes/factory_and_singleton_003.phpt b/tests/classes/factory_and_singleton_003.phpt
new file mode 100644
index 0000000..3d50a81
--- /dev/null
+++ b/tests/classes/factory_and_singleton_003.phpt
@@ -0,0 +1,18 @@
+--TEST--
+ZE2 factory and singleton, test 3
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ protected function __construct($x) {
+ }
+}
+
+$obj = new test;
+
+echo "Done\n";
+?>
+--EXPECTF--
+Fatal error: Call to protected test::__construct() from invalid context in %s on line %d
diff --git a/tests/classes/factory_and_singleton_004.phpt b/tests/classes/factory_and_singleton_004.phpt
new file mode 100644
index 0000000..14edcb1
--- /dev/null
+++ b/tests/classes/factory_and_singleton_004.phpt
@@ -0,0 +1,18 @@
+--TEST--
+ZE2 factory and singleton, test 4
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ private function __construct($x) {
+ }
+}
+
+$obj = new test;
+
+echo "Done\n";
+?>
+--EXPECTF--
+Fatal error: Call to private test::__construct() from invalid context in %s on line %d
diff --git a/tests/classes/factory_and_singleton_005.phpt b/tests/classes/factory_and_singleton_005.phpt
new file mode 100644
index 0000000..2cd7e5c
--- /dev/null
+++ b/tests/classes/factory_and_singleton_005.phpt
@@ -0,0 +1,19 @@
+--TEST--
+ZE2 factory and singleton, test 5
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ protected function __destruct() {
+ }
+}
+
+$obj = new test;
+$obj = NULL;
+
+echo "Done\n";
+?>
+--EXPECTF--
+Fatal error: Call to protected test::__destruct() from context '' in %sfactory_and_singleton_005.php on line %d
diff --git a/tests/classes/factory_and_singleton_006.phpt b/tests/classes/factory_and_singleton_006.phpt
new file mode 100644
index 0000000..81cf714
--- /dev/null
+++ b/tests/classes/factory_and_singleton_006.phpt
@@ -0,0 +1,20 @@
+--TEST--
+ZE2 factory and singleton, test 6
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ private function __destruct() {
+ }
+}
+
+$obj = new test;
+$obj = NULL;
+
+echo "Done\n";
+?>
+--EXPECTF--
+Fatal error: Call to private test::__destruct() from context '' in %sfactory_and_singleton_006.php on line %d
+
diff --git a/tests/classes/factory_and_singleton_007.phpt b/tests/classes/factory_and_singleton_007.phpt
new file mode 100644
index 0000000..4788dbf
--- /dev/null
+++ b/tests/classes/factory_and_singleton_007.phpt
@@ -0,0 +1,20 @@
+--TEST--
+ZE2 factory and singleton, test 7
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ protected function __clone() {
+ }
+}
+
+$obj = new test;
+$clone = clone $obj;
+$obj = NULL;
+
+echo "Done\n";
+?>
+--EXPECTF--
+Fatal error: Call to protected test::__clone() from context '' %sfactory_and_singleton_007.php on line %d
diff --git a/tests/classes/factory_and_singleton_008.phpt b/tests/classes/factory_and_singleton_008.phpt
new file mode 100644
index 0000000..750b9db
--- /dev/null
+++ b/tests/classes/factory_and_singleton_008.phpt
@@ -0,0 +1,20 @@
+--TEST--
+ZE2 factory and singleton, test 8
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ private function __clone() {
+ }
+}
+
+$obj = new test;
+$clone = clone $obj;
+$obj = NULL;
+
+echo "Done\n";
+?>
+--EXPECTF--
+Fatal error: Call to private test::__clone() from context '' %sfactory_and_singleton_008.php on line %d
diff --git a/tests/classes/factory_and_singleton_009.phpt b/tests/classes/factory_and_singleton_009.phpt
new file mode 100644
index 0000000..acf792c
--- /dev/null
+++ b/tests/classes/factory_and_singleton_009.phpt
@@ -0,0 +1,21 @@
+--TEST--
+ZE2 factory and singleton, test 9
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ protected function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+$obj = new test;
+
+?>
+===DONE===
+--EXPECTF--
+===DONE===
+
+Warning: Call to protected test::__destruct() from context '' during shutdown ignored in Unknown on line 0
diff --git a/tests/classes/factory_and_singleton_010.phpt b/tests/classes/factory_and_singleton_010.phpt
new file mode 100644
index 0000000..0f5fb2d
--- /dev/null
+++ b/tests/classes/factory_and_singleton_010.phpt
@@ -0,0 +1,21 @@
+--TEST--
+ZE2 factory and singleton, test 10
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class test {
+
+ private function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+$obj = new test;
+
+?>
+===DONE===
+--EXPECTF--
+===DONE===
+
+Warning: Call to private test::__destruct() from context '' during shutdown ignored in Unknown on line 0
diff --git a/tests/classes/final.phpt b/tests/classes/final.phpt
new file mode 100644
index 0000000..b4e37a3
--- /dev/null
+++ b/tests/classes/final.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 A method may be redeclared final
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class first {
+ function show() {
+ echo "Call to function first::show()\n";
+ }
+}
+
+$t = new first();
+$t->show();
+
+class second extends first {
+ final function show() {
+ echo "Call to function second::show()\n";
+ }
+}
+
+$t2 = new second();
+$t2->show();
+
+echo "Done\n";
+?>
+--EXPECTF--
+Call to function first::show()
+Call to function second::show()
+Done \ No newline at end of file
diff --git a/tests/classes/final_abstract.phpt b/tests/classes/final_abstract.phpt
new file mode 100644
index 0000000..426c852
--- /dev/null
+++ b/tests/classes/final_abstract.phpt
@@ -0,0 +1,16 @@
+--TEST--
+ZE2 A final method cannot be abstract
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class fail {
+ final abstract function show();
+}
+
+echo "Done\n"; // Shouldn't be displayed
+?>
+--EXPECTF--
+
+Fatal error: Cannot use the final modifier on an abstract class member in %s
diff --git a/tests/classes/final_ctor1.phpt b/tests/classes/final_ctor1.phpt
new file mode 100644
index 0000000..ebfa080
--- /dev/null
+++ b/tests/classes/final_ctor1.phpt
@@ -0,0 +1,29 @@
+--TEST--
+ZE2 cannot override final __construct
+--FILE--
+<?php
+
+class Base
+{
+ public final function __construct()
+ {
+ }
+}
+
+class Works extends Base
+{
+}
+
+class Extended extends Base
+{
+ public function Extended()
+ {
+ }
+}
+
+ReflectionClass::export('Extended');
+
+?>
+--EXPECTF--
+
+Fatal error: Cannot override final Base::__construct() with Extended::Extended() in %sfinal_ctor1.php on line %d
diff --git a/tests/classes/final_ctor2.phpt b/tests/classes/final_ctor2.phpt
new file mode 100644
index 0000000..905337b
--- /dev/null
+++ b/tests/classes/final_ctor2.phpt
@@ -0,0 +1,29 @@
+--TEST--
+ZE2 cannot override final old style ctor
+--FILE--
+<?php
+
+class Base
+{
+ public final function Base()
+ {
+ }
+}
+
+class Works extends Base
+{
+}
+
+class Extended extends Base
+{
+ public function __construct()
+ {
+ }
+}
+
+ReflectionClass::export('Extended');
+
+?>
+--EXPECTF--
+
+Fatal error: Cannot override final Base::Base() with Extended::__construct() in %sfinal_ctor2.php on line %d
diff --git a/tests/classes/final_ctor3.phpt b/tests/classes/final_ctor3.phpt
new file mode 100644
index 0000000..3a61ecf
--- /dev/null
+++ b/tests/classes/final_ctor3.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Ensure implicit final inherited old-style constructor cannot be overridden.
+--FILE--
+<?php
+ class A {
+ final function A() { }
+ }
+ class B extends A {
+ function A() { }
+ }
+?>
+--EXPECTF--
+Fatal error: Cannot override final method A::A() in %s on line %d
diff --git a/tests/classes/final_redeclare.phpt b/tests/classes/final_redeclare.phpt
new file mode 100644
index 0000000..e8f2e6f
--- /dev/null
+++ b/tests/classes/final_redeclare.phpt
@@ -0,0 +1,25 @@
+--TEST--
+ZE2 A final method may not be overwritten
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ final function show() {
+ echo "Call to function pass::show()\n";
+ }
+}
+
+$t = new pass();
+
+class fail extends pass {
+ function show() {
+ echo "Call to function fail::show()\n";
+ }
+}
+
+echo "Done\n"; // Shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Cannot override final method pass::show() in %s on line %d
diff --git a/tests/classes/implicit_instantiation_001.phpt b/tests/classes/implicit_instantiation_001.phpt
new file mode 100644
index 0000000..8d2f32d
--- /dev/null
+++ b/tests/classes/implicit_instantiation_001.phpt
@@ -0,0 +1,146 @@
+--TEST--
+Implicit object instantiation when accessing properties of non-object.
+--FILE--
+<?php
+class C {
+ // These values get implicitly converted to objects
+ public $boolFalse = false;
+ public $emptyString = '';
+ public $null = null;
+
+ // These values do not get implicitly converted to objects
+ public $boolTrue = true;
+ public $nonEmptyString = 'hello';
+ public $intZero = 0;
+}
+
+$c = new C;
+foreach($c as $name => $value) {
+ echo "\n\n---( \$c->$name )---";
+ echo "\n --> Attempting implicit conversion to object using increment...\n";
+ $c->$name->prop++;
+ $c->$name = $value; // reset value in case implicit conversion was successful
+
+ echo "\n --> Attempting implicit conversion to object using assignment...\n";
+ $c->$name->prop = "Implicit instantiation!";
+ $c->$name = $value; // reset value in case implicit conversion was successful
+
+ echo "\n --> Attempting implicit conversion to object using combined assignment...\n";
+ $c->$name->prop .= " Implicit instantiation!";
+}
+
+echo "\n\n\n --> Resulting object:";
+var_dump($c);
+
+?>
+--EXPECTF--
+
+
+---( $c->boolFalse )---
+ --> Attempting implicit conversion to object using increment...
+
+Warning: Creating default object from empty value in %s on line 18
+
+ --> Attempting implicit conversion to object using assignment...
+
+Warning: Creating default object from empty value in %s on line 22
+
+ --> Attempting implicit conversion to object using combined assignment...
+
+Warning: Creating default object from empty value in %s on line 26
+
+
+---( $c->emptyString )---
+ --> Attempting implicit conversion to object using increment...
+
+Warning: Creating default object from empty value in %s on line 18
+
+ --> Attempting implicit conversion to object using assignment...
+
+Warning: Creating default object from empty value in %s on line 22
+
+ --> Attempting implicit conversion to object using combined assignment...
+
+Warning: Creating default object from empty value in %s on line 26
+
+
+---( $c->null )---
+ --> Attempting implicit conversion to object using increment...
+
+Warning: Creating default object from empty value in %s on line 18
+
+ --> Attempting implicit conversion to object using assignment...
+
+Warning: Creating default object from empty value in %s on line 22
+
+ --> Attempting implicit conversion to object using combined assignment...
+
+Warning: Creating default object from empty value in %s on line 26
+
+
+---( $c->boolTrue )---
+ --> Attempting implicit conversion to object using increment...
+
+Warning: Attempt to %s property of non-object in %s on line 18
+
+ --> Attempting implicit conversion to object using assignment...
+
+Warning: Attempt to assign property of non-object in %s on line 22
+
+ --> Attempting implicit conversion to object using combined assignment...
+
+Warning: Attempt to assign property of non-object in %s on line 26
+
+
+---( $c->nonEmptyString )---
+ --> Attempting implicit conversion to object using increment...
+
+Warning: Attempt to %s property of non-object in %s on line 18
+
+ --> Attempting implicit conversion to object using assignment...
+
+Warning: Attempt to assign property of non-object in %s on line 22
+
+ --> Attempting implicit conversion to object using combined assignment...
+
+Warning: Attempt to assign property of non-object in %s on line 26
+
+
+---( $c->intZero )---
+ --> Attempting implicit conversion to object using increment...
+
+Warning: Attempt to %s property of non-object in %s on line 18
+
+ --> Attempting implicit conversion to object using assignment...
+
+Warning: Attempt to assign property of non-object in %s on line 22
+
+ --> Attempting implicit conversion to object using combined assignment...
+
+Warning: Attempt to assign property of non-object in %s on line 26
+
+
+
+ --> Resulting object:object(C)#%d (6) {
+ [%u|b%"boolFalse"]=>
+ object(stdClass)#%d (1) {
+ [%u|b%"prop"]=>
+ %unicode|string%(24) " Implicit instantiation!"
+ }
+ [%u|b%"emptyString"]=>
+ object(stdClass)#%d (1) {
+ [%u|b%"prop"]=>
+ %unicode|string%(24) " Implicit instantiation!"
+ }
+ [%u|b%"null"]=>
+ object(stdClass)#%d (1) {
+ [%u|b%"prop"]=>
+ %unicode|string%(24) " Implicit instantiation!"
+ }
+ [%u|b%"boolTrue"]=>
+ bool(true)
+ [%u|b%"nonEmptyString"]=>
+ %unicode|string%(5) "hello"
+ [%u|b%"intZero"]=>
+ int(0)
+} \ No newline at end of file
diff --git a/tests/classes/incdec_property_001.phpt b/tests/classes/incdec_property_001.phpt
new file mode 100644
index 0000000..97a24d3
--- /dev/null
+++ b/tests/classes/incdec_property_001.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 post increment/decrement property of overloaded object
+--FILE--
+<?php
+
+class Test {
+ private $real_a = 2;
+
+ function __set($property, $value) {
+ if ($property == "a") {
+ $this->real_a = $value;
+ }
+ }
+
+ function __get($property) {
+ if ($property == "a") {
+ return $this->real_a;
+ }
+ }
+}
+
+$obj = new Test;
+var_dump($obj->a);
+$obj->a++;
+var_dump($obj->a);
+echo "---Done---\n";
+?>
+--EXPECT--
+int(2)
+int(3)
+---Done---
diff --git a/tests/classes/incdec_property_002.phpt b/tests/classes/incdec_property_002.phpt
new file mode 100644
index 0000000..c1d7dde
--- /dev/null
+++ b/tests/classes/incdec_property_002.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 post increment/decrement property of overloaded object with assignment
+--FILE--
+<?php
+
+class Test {
+ private $real_a = 2;
+
+ function __set($property, $value) {
+ if ($property == "a") {
+ $this->real_a = $value;
+ }
+ }
+
+ function __get($property) {
+ if ($property == "a") {
+ return $this->real_a;
+ }
+ }
+}
+
+$obj = new Test;
+var_dump($obj->a);
+$t1 = $obj->a++;
+var_dump($obj->a);
+echo "---Done---\n";
+?>
+--EXPECT--
+int(2)
+int(3)
+---Done---
diff --git a/tests/classes/incdec_property_003.phpt b/tests/classes/incdec_property_003.phpt
new file mode 100644
index 0000000..1a92384
--- /dev/null
+++ b/tests/classes/incdec_property_003.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 pre increment/decrement property of overloaded object
+--FILE--
+<?php
+
+class Test {
+ private $real_a = 2;
+
+ function __set($property, $value) {
+ if ($property == "a") {
+ $this->real_a = $value;
+ }
+ }
+
+ function __get($property) {
+ if ($property == "a") {
+ return $this->real_a;
+ }
+ }
+}
+
+$obj = new Test;
+var_dump($obj->a);
+++$obj->a;
+var_dump($obj->a);
+echo "---Done---\n";
+?>
+--EXPECT--
+int(2)
+int(3)
+---Done---
diff --git a/tests/classes/incdec_property_004.phpt b/tests/classes/incdec_property_004.phpt
new file mode 100644
index 0000000..05e3b44
--- /dev/null
+++ b/tests/classes/incdec_property_004.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 pre increment/decrement property of overloaded object with assignment
+--FILE--
+<?php
+
+class Test {
+ private $real_a = 2;
+
+ function __set($property, $value) {
+ if ($property == "a") {
+ $this->real_a = $value;
+ }
+ }
+
+ function __get($property) {
+ if ($property == "a") {
+ return $this->real_a;
+ }
+ }
+}
+
+$obj = new Test;
+var_dump($obj->a);
+$t1 = ++$obj->a;
+var_dump($obj->a);
+echo "---Done---\n";
+?>
+--EXPECT--
+int(2)
+int(3)
+---Done---
diff --git a/tests/classes/inheritance.phpt b/tests/classes/inheritance.phpt
new file mode 100644
index 0000000..070ad91
--- /dev/null
+++ b/tests/classes/inheritance.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Classes inheritance test
+--FILE--
+<?php
+
+/* Inheritance test. Pretty nifty if I do say so myself! */
+
+class foo {
+ public $a;
+ public $b;
+ function display() {
+ echo "This is class foo\n";
+ echo "a = ".$this->a."\n";
+ echo "b = ".$this->b."\n";
+ }
+ function mul() {
+ return $this->a*$this->b;
+ }
+};
+
+class bar extends foo {
+ public $c;
+ function display() { /* alternative display function for class bar */
+ echo "This is class bar\n";
+ echo "a = ".$this->a."\n";
+ echo "b = ".$this->b."\n";
+ echo "c = ".$this->c."\n";
+ }
+};
+
+
+$foo1 = new foo;
+$foo1->a = 2;
+$foo1->b = 5;
+$foo1->display();
+echo $foo1->mul()."\n";
+
+echo "-----\n";
+
+$bar1 = new bar;
+$bar1->a = 4;
+$bar1->b = 3;
+$bar1->c = 12;
+$bar1->display();
+echo $bar1->mul()."\n";
+--EXPECT--
+This is class foo
+a = 2
+b = 5
+10
+-----
+This is class bar
+a = 4
+b = 3
+c = 12
+12
diff --git a/tests/classes/inheritance_002.phpt b/tests/classes/inheritance_002.phpt
new file mode 100644
index 0000000..cca528e
--- /dev/null
+++ b/tests/classes/inheritance_002.phpt
@@ -0,0 +1,71 @@
+--TEST--
+ZE2 Constructor precedence
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class Base_php4 {
+ function Base_php4() {
+ var_dump('Base constructor');
+ }
+}
+
+class Child_php4 extends Base_php4 {
+ function Child_php4() {
+ var_dump('Child constructor');
+ parent::Base_php4();
+ }
+}
+
+class Base_php5 {
+ function __construct() {
+ var_dump('Base constructor');
+ }
+ }
+
+class Child_php5 extends Base_php5 {
+ function __construct() {
+ var_dump('Child constructor');
+ parent::__construct();
+ }
+ }
+
+class Child_mx1 extends Base_php4 {
+ function __construct() {
+ var_dump('Child constructor');
+ parent::Base_php4();
+ }
+}
+
+class Child_mx2 extends Base_php5 {
+ function Child_mx2() {
+ var_dump('Child constructor');
+ parent::__construct();
+ }
+}
+
+echo "### PHP 4 style\n";
+$c4= new Child_php4();
+
+echo "### PHP 5 style\n";
+$c5= new Child_php5();
+
+echo "### Mixed style 1\n";
+$cm= new Child_mx1();
+
+echo "### Mixed style 2\n";
+$cm= new Child_mx2();
+?>
+--EXPECT--
+### PHP 4 style
+string(17) "Child constructor"
+string(16) "Base constructor"
+### PHP 5 style
+string(17) "Child constructor"
+string(16) "Base constructor"
+### Mixed style 1
+string(17) "Child constructor"
+string(16) "Base constructor"
+### Mixed style 2
+string(17) "Child constructor"
+string(16) "Base constructor"
diff --git a/tests/classes/inheritance_003.phpt b/tests/classes/inheritance_003.phpt
new file mode 100644
index 0000000..1f4eafa
--- /dev/null
+++ b/tests/classes/inheritance_003.phpt
@@ -0,0 +1,21 @@
+--TEST--
+ZE2 method inheritance without interfaces
+--FILE--
+<?php
+
+class A
+{
+ function f($x) {}
+}
+
+class B extends A
+{
+ function f() {}
+}
+
+?>
+===DONE===
+--EXPECTF--
+
+Strict Standards: Declaration of B::f() should be compatible with A::f($x) in %sinheritance_003.php on line %d
+===DONE===
diff --git a/tests/classes/inheritance_004.phpt b/tests/classes/inheritance_004.phpt
new file mode 100644
index 0000000..d1f5faf
--- /dev/null
+++ b/tests/classes/inheritance_004.phpt
@@ -0,0 +1,21 @@
+--TEST--
+ZE2 method inheritance without interfaces
+--FILE--
+<?php
+
+class A
+{
+ function f() {}
+}
+
+class B extends A
+{
+ function f($x) {}
+}
+
+?>
+===DONE===
+--EXPECTF--
+
+Strict Standards: Declaration of B::f() should be compatible with A::f() in %sinheritance_004.php on line %d
+===DONE===
diff --git a/tests/classes/inheritance_005.phpt b/tests/classes/inheritance_005.phpt
new file mode 100644
index 0000000..8990264
--- /dev/null
+++ b/tests/classes/inheritance_005.phpt
@@ -0,0 +1,57 @@
+--TEST--
+Check for inherited old-style constructor.
+--FILE--
+<?php
+ class A
+ {
+ function A()
+ {
+ echo "In " . __METHOD__ . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ }
+
+ class C extends B
+ {
+ }
+
+
+ echo "About to construct new B: \n";
+ $b = new B;
+
+ echo "Is B::B() callable?\n";
+ var_dump(is_callable(array($b, "B")));
+
+ echo "Is B::A() callable?\n";
+ var_dump(is_callable(array($b, "A")));
+
+ echo "About to construct new C: \n";
+ $c = new C;
+
+ echo "Is C::A() callable?\n";
+ var_dump(is_callable(array($c, "A")));
+
+ echo "Is C::B() callable?\n";
+ var_dump(is_callable(array($c, "B")));
+
+ echo "Is C::C() callable?\n";
+ var_dump(is_callable(array($c, "C")));
+?>
+--EXPECTF--
+About to construct new B:
+In A::A
+Is B::B() callable?
+bool(false)
+Is B::A() callable?
+bool(true)
+About to construct new C:
+In A::A
+Is C::A() callable?
+bool(true)
+Is C::B() callable?
+bool(false)
+Is C::C() callable?
+bool(false)
diff --git a/tests/classes/inheritance_006.phpt b/tests/classes/inheritance_006.phpt
new file mode 100644
index 0000000..d51dafe
--- /dev/null
+++ b/tests/classes/inheritance_006.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Private property inheritance check
+--FILE--
+<?php
+Class A {
+ private $c;
+}
+
+Class B extends A {
+ private $c;
+}
+
+Class C extends B {
+}
+
+var_dump(new C);
+?>
+--EXPECTF--
+object(C)#%d (2) {
+ [%u|b%"c":%u|b%"B":private]=>
+ NULL
+ [%u|b%"c":%u|b%"A":private]=>
+ NULL
+} \ No newline at end of file
diff --git a/tests/classes/inheritance_007.phpt b/tests/classes/inheritance_007.phpt
new file mode 100644
index 0000000..0b2bde0
--- /dev/null
+++ b/tests/classes/inheritance_007.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Ensure inherited old-style constructor doesn't block other methods
+--FILE--
+<?php
+class A {
+ public function B () { echo "In " . __METHOD__ . "\n"; }
+ public function A () { echo "In " . __METHOD__ . "\n"; }
+}
+class B extends A { }
+
+$rc = new ReflectionClass('B');
+var_dump($rc->getMethods());
+
+
+$b = new B();
+$b->a();
+$b->b();
+
+?>
+--EXPECTF--
+array(2) {
+ [0]=>
+ &object(ReflectionMethod)#%d (2) {
+ ["name"]=>
+ string(1) "B"
+ ["class"]=>
+ string(1) "A"
+ }
+ [1]=>
+ &object(ReflectionMethod)#%d (2) {
+ ["name"]=>
+ string(1) "A"
+ ["class"]=>
+ string(1) "A"
+ }
+}
+In A::A
+In A::A
+In A::B
diff --git a/tests/classes/interface_and_extends.phpt b/tests/classes/interface_and_extends.phpt
new file mode 100644
index 0000000..f9040ae
--- /dev/null
+++ b/tests/classes/interface_and_extends.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 a class cannot extend an interface
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface Test
+{
+ function show();
+}
+
+class Tester extends Test
+{
+ function show() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+$o = new Tester;
+$o->show();
+
+?>
+===DONE===
+--EXPECTF--
+Fatal error: Class Tester cannot extend from interface Test in %sinterface_and_extends.php on line %d
diff --git a/tests/classes/interface_class.phpt b/tests/classes/interface_class.phpt
new file mode 100644
index 0000000..22520de
--- /dev/null
+++ b/tests/classes/interface_class.phpt
@@ -0,0 +1,14 @@
+--TEST--
+ZE2 A class can only implement interfaces
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class base {
+}
+
+class derived implements base {
+}
+?>
+--EXPECTF--
+Fatal error: derived cannot implement base - it is not an interface in %s on line %d
diff --git a/tests/classes/interface_constant_inheritance_001.phpt b/tests/classes/interface_constant_inheritance_001.phpt
new file mode 100644
index 0000000..f982a4a
--- /dev/null
+++ b/tests/classes/interface_constant_inheritance_001.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Ensure an interface may not shadow an inherited constant.
+--FILE--
+<?php
+interface I1 {
+ const FOO = 10;
+}
+
+interface I2 extends I1 {
+ const FOO = 10;
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+
+Fatal error: Cannot inherit previously-inherited or override constant FOO from interface I1 in %s on line 6
diff --git a/tests/classes/interface_constant_inheritance_002.phpt b/tests/classes/interface_constant_inheritance_002.phpt
new file mode 100644
index 0000000..af4ce69
--- /dev/null
+++ b/tests/classes/interface_constant_inheritance_002.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Ensure a class may not shadow a constant inherited from an interface.
+--FILE--
+<?php
+interface I {
+ const FOO = 10;
+}
+
+class C implements I {
+ const FOO = 10;
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+
+Fatal error: Cannot inherit previously-inherited or override constant FOO from interface I in %s on line 6
diff --git a/tests/classes/interface_constant_inheritance_003.phpt b/tests/classes/interface_constant_inheritance_003.phpt
new file mode 100644
index 0000000..6b4139b
--- /dev/null
+++ b/tests/classes/interface_constant_inheritance_003.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Ensure a class may not inherit two constants with the same name from two separate interfaces.
+--FILE--
+<?php
+interface I1 {
+ const FOO = 10;
+}
+
+interface I2 {
+ const FOO = 10;
+}
+
+class C implements I1,I2 {
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+
+Fatal error: Cannot inherit previously-inherited or override constant FOO from interface I2 in %s on line 10
diff --git a/tests/classes/interface_constant_inheritance_004.phpt b/tests/classes/interface_constant_inheritance_004.phpt
new file mode 100644
index 0000000..f055929
--- /dev/null
+++ b/tests/classes/interface_constant_inheritance_004.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Ensure a class may implement two interfaces which include the same constant (due to inheritance).
+--FILE--
+<?php
+interface IA {
+ const FOO = 10;
+}
+
+interface IB extends IA {
+}
+
+class C implements IA, IB {
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/interface_doubled.phpt b/tests/classes/interface_doubled.phpt
new file mode 100644
index 0000000..e1dd31f
--- /dev/null
+++ b/tests/classes/interface_doubled.phpt
@@ -0,0 +1,201 @@
+--TEST--
+ZE2 An interface extends base interfaces
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+ function f_a();
+}
+
+interface if_b {
+ function f_b();
+}
+
+interface if_c extends if_a, if_b {
+ function f_c();
+}
+
+interface if_d extends if_a, if_b {
+ function f_d();
+}
+
+interface if_e {
+ function f_d();
+}
+
+interface if_f extends /*if_e,*/ if_a, if_b, if_c, if_d /*, if_e*/ {
+}
+
+class base {
+ function test($class) {
+ echo "is_a(" . get_class($this) . ", $class) ". (($this instanceof $class) ? "yes\n" : "no\n");
+ }
+}
+
+echo "class_a\n";
+
+class class_a extends base implements if_a {
+ function f_a() {}
+ function f_b() {}
+ function f_c() {}
+ function f_d() {}
+ function f_e() {}
+}
+
+$t = new class_a();
+echo $t->test('if_a');
+echo $t->test('if_b');
+echo $t->test('if_c');
+echo $t->test('if_d');
+echo $t->test('if_e');
+
+echo "class_b\n";
+
+class class_b extends base implements if_a, if_b {
+ function f_a() {}
+ function f_b() {}
+ function f_c() {}
+ function f_d() {}
+ function f_e() {}
+}
+
+$t = new class_b();
+echo $t->test('if_a');
+echo $t->test('if_b');
+echo $t->test('if_c');
+echo $t->test('if_d');
+echo $t->test('if_e');
+
+echo "class_c\n";
+
+class class_c extends base implements if_c {
+ function f_a() {}
+ function f_b() {}
+ function f_c() {}
+ function f_d() {}
+ function f_e() {}
+}
+
+$t = new class_c();
+echo $t->test('if_a');
+echo $t->test('if_b');
+echo $t->test('if_c');
+echo $t->test('if_d');
+echo $t->test('if_e');
+
+echo "class_d\n";
+
+class class_d extends base implements if_d{
+ function f_a() {}
+ function f_b() {}
+ function f_c() {}
+ function f_d() {}
+ function f_e() {}
+}
+
+$t = new class_d();
+echo $t->test('if_a');
+echo $t->test('if_b');
+echo $t->test('if_c');
+echo $t->test('if_d');
+echo $t->test('if_e');
+
+echo "class_e\n";
+
+class class_e extends base implements if_a, if_b, if_c, if_d {
+ function f_a() {}
+ function f_b() {}
+ function f_c() {}
+ function f_d() {}
+ function f_e() {}
+}
+
+$t = new class_e();
+echo $t->test('if_a');
+echo $t->test('if_b');
+echo $t->test('if_c');
+echo $t->test('if_d');
+echo $t->test('if_e');
+
+echo "class_f\n";
+
+class class_f extends base implements if_e {
+ function f_a() {}
+ function f_b() {}
+ function f_c() {}
+ function f_d() {}
+ function f_e() {}
+}
+
+$t = new class_f();
+echo $t->test('if_a');
+echo $t->test('if_b');
+echo $t->test('if_c');
+echo $t->test('if_d');
+echo $t->test('if_e');
+
+echo "class_g\n";
+
+class class_g extends base implements if_f {
+ function f_a() {}
+ function f_b() {}
+ function f_c() {}
+ function f_d() {}
+ function f_e() {}
+}
+
+$t = new class_g();
+echo $t->test('if_a');
+echo $t->test('if_b');
+echo $t->test('if_c');
+echo $t->test('if_d');
+echo $t->test('if_e');
+
+?>
+===DONE===
+--EXPECTF--
+class_a
+is_a(class_a, if_a) yes
+is_a(class_a, if_b) no
+is_a(class_a, if_c) no
+is_a(class_a, if_d) no
+is_a(class_a, if_e) no
+class_b
+is_a(class_b, if_a) yes
+is_a(class_b, if_b) yes
+is_a(class_b, if_c) no
+is_a(class_b, if_d) no
+is_a(class_b, if_e) no
+class_c
+is_a(class_c, if_a) yes
+is_a(class_c, if_b) yes
+is_a(class_c, if_c) yes
+is_a(class_c, if_d) no
+is_a(class_c, if_e) no
+class_d
+is_a(class_d, if_a) yes
+is_a(class_d, if_b) yes
+is_a(class_d, if_c) no
+is_a(class_d, if_d) yes
+is_a(class_d, if_e) no
+class_e
+is_a(class_e, if_a) yes
+is_a(class_e, if_b) yes
+is_a(class_e, if_c) yes
+is_a(class_e, if_d) yes
+is_a(class_e, if_e) no
+class_f
+is_a(class_f, if_a) no
+is_a(class_f, if_b) no
+is_a(class_f, if_c) no
+is_a(class_f, if_d) no
+is_a(class_f, if_e) yes
+class_g
+is_a(class_g, if_a) yes
+is_a(class_g, if_b) yes
+is_a(class_g, if_c) yes
+is_a(class_g, if_d) yes
+is_a(class_g, if_e) no
+===DONE===
diff --git a/tests/classes/interface_implemented.phpt b/tests/classes/interface_implemented.phpt
new file mode 100644
index 0000000..e33a4da
--- /dev/null
+++ b/tests/classes/interface_implemented.phpt
@@ -0,0 +1,103 @@
+--TEST--
+ZE2 An interface is inherited
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+ function f_a();
+}
+
+interface if_b extends if_a {
+ function f_b();
+}
+
+class base {
+ function _is_a($sub) {
+ echo 'is_a('.get_class($this).', '.$sub.') = '.(($this instanceof $sub) ? 'yes' : 'no')."\n";
+ }
+ function test() {
+ echo $this->_is_a('base');
+ echo $this->_is_a('derived_a');
+ echo $this->_is_a('derived_b');
+ echo $this->_is_a('derived_c');
+ echo $this->_is_a('derived_d');
+ echo $this->_is_a('if_a');
+ echo $this->_is_a('if_b');
+ echo "\n";
+ }
+}
+
+class derived_a extends base implements if_a {
+ function f_a() {}
+}
+
+class derived_b extends base implements if_a, if_b {
+ function f_a() {}
+ function f_b() {}
+}
+
+class derived_c extends derived_a implements if_b {
+ function f_b() {}
+}
+
+class derived_d extends derived_c {
+}
+
+$t = new base();
+$t->test();
+
+$t = new derived_a();
+$t->test();
+
+$t = new derived_b();
+$t->test();
+
+$t = new derived_c();
+$t->test();
+
+$t = new derived_d();
+$t->test();
+
+?>
+--EXPECTF--
+is_a(base, base) = yes
+is_a(base, derived_a) = no
+is_a(base, derived_b) = no
+is_a(base, derived_c) = no
+is_a(base, derived_d) = no
+is_a(base, if_a) = no
+is_a(base, if_b) = no
+
+is_a(derived_a, base) = yes
+is_a(derived_a, derived_a) = yes
+is_a(derived_a, derived_b) = no
+is_a(derived_a, derived_c) = no
+is_a(derived_a, derived_d) = no
+is_a(derived_a, if_a) = yes
+is_a(derived_a, if_b) = no
+
+is_a(derived_b, base) = yes
+is_a(derived_b, derived_a) = no
+is_a(derived_b, derived_b) = yes
+is_a(derived_b, derived_c) = no
+is_a(derived_b, derived_d) = no
+is_a(derived_b, if_a) = yes
+is_a(derived_b, if_b) = yes
+
+is_a(derived_c, base) = yes
+is_a(derived_c, derived_a) = yes
+is_a(derived_c, derived_b) = no
+is_a(derived_c, derived_c) = yes
+is_a(derived_c, derived_d) = no
+is_a(derived_c, if_a) = yes
+is_a(derived_c, if_b) = yes
+
+is_a(derived_d, base) = yes
+is_a(derived_d, derived_a) = yes
+is_a(derived_d, derived_b) = no
+is_a(derived_d, derived_c) = yes
+is_a(derived_d, derived_d) = yes
+is_a(derived_d, if_a) = yes
+is_a(derived_d, if_b) = yes
diff --git a/tests/classes/interface_instantiate.phpt b/tests/classes/interface_instantiate.phpt
new file mode 100644
index 0000000..61c4e6b
--- /dev/null
+++ b/tests/classes/interface_instantiate.phpt
@@ -0,0 +1,16 @@
+--TEST--
+ZE2 An interface cannot be instantiated
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+ function f_a();
+}
+
+$t = new if_a();
+
+?>
+--EXPECTF--
+Fatal error: Cannot instantiate interface if_a in %s on line %d
diff --git a/tests/classes/interface_member.phpt b/tests/classes/interface_member.phpt
new file mode 100644
index 0000000..329c072
--- /dev/null
+++ b/tests/classes/interface_member.phpt
@@ -0,0 +1,13 @@
+--TEST--
+ZE2 An interface cannot have properties
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+ public $member;
+}
+?>
+--EXPECTF--
+Fatal error: Interfaces may not include member variables in %s on line %d
diff --git a/tests/classes/interface_method.phpt b/tests/classes/interface_method.phpt
new file mode 100644
index 0000000..3570b35
--- /dev/null
+++ b/tests/classes/interface_method.phpt
@@ -0,0 +1,15 @@
+--TEST--
+ZE2 An interface method must be abstract
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+ function err() {};
+}
+
+?>
+--EXPECTF--
+
+Fatal error: Interface function if_a::err() cannot contain body %s on line %d
diff --git a/tests/classes/interface_method_final.phpt b/tests/classes/interface_method_final.phpt
new file mode 100644
index 0000000..01e599c
--- /dev/null
+++ b/tests/classes/interface_method_final.phpt
@@ -0,0 +1,15 @@
+--TEST--
+ZE2 An interface method cannot be final
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class if_a {
+ abstract final function err();
+}
+
+?>
+--EXPECTF--
+
+Fatal error: Cannot use the final modifier on an abstract class member in %s on line %d
diff --git a/tests/classes/interface_method_private.phpt b/tests/classes/interface_method_private.phpt
new file mode 100644
index 0000000..aa46a03
--- /dev/null
+++ b/tests/classes/interface_method_private.phpt
@@ -0,0 +1,15 @@
+--TEST--
+ZE2 An interface method cannot be private
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+ abstract private function err();
+}
+
+?>
+--EXPECTF--
+
+Fatal error: Access type for interface method if_a::err() must be omitted in %s on line %d
diff --git a/tests/classes/interface_must_be_implemented.phpt b/tests/classes/interface_must_be_implemented.phpt
new file mode 100644
index 0000000..a4d7970
--- /dev/null
+++ b/tests/classes/interface_must_be_implemented.phpt
@@ -0,0 +1,17 @@
+--TEST--
+ZE2 An interface must be implemented
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+ function f_a();
+}
+
+class derived_a implements if_a {
+}
+
+?>
+--EXPECTF--
+Fatal error: Class derived_a contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (if_a::f_a) in %s on line %d
diff --git a/tests/classes/interface_optional_arg.phpt b/tests/classes/interface_optional_arg.phpt
new file mode 100644
index 0000000..05f2fc4
--- /dev/null
+++ b/tests/classes/interface_optional_arg.phpt
@@ -0,0 +1,27 @@
+--TEST--
+ZE2 An interface method allows additional default arguments
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+error_reporting(4095);
+
+interface test {
+ public function bar();
+}
+
+class foo implements test {
+
+ public function bar($foo = NULL) {
+ echo "foo\n";
+ }
+}
+
+$foo = new foo;
+$foo->bar();
+
+?>
+--EXPECT--
+foo
+
diff --git a/tests/classes/interface_optional_arg_002.phpt b/tests/classes/interface_optional_arg_002.phpt
new file mode 100644
index 0000000..92980f6
--- /dev/null
+++ b/tests/classes/interface_optional_arg_002.phpt
@@ -0,0 +1,24 @@
+--TEST--
+default argument value in interface implementation
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface test {
+ public function bar();
+}
+
+class foo implements test {
+
+ public function bar($arg = 2) {
+ var_dump($arg);
+ }
+}
+
+$foo = new foo;
+$foo->bar();
+
+?>
+--EXPECT--
+int(2) \ No newline at end of file
diff --git a/tests/classes/interface_optional_arg_003.inc b/tests/classes/interface_optional_arg_003.inc
new file mode 100644
index 0000000..a62c656
--- /dev/null
+++ b/tests/classes/interface_optional_arg_003.inc
@@ -0,0 +1,4 @@
+<?php
+interface I {
+ function f($a = null);
+} \ No newline at end of file
diff --git a/tests/classes/interface_optional_arg_003.phpt b/tests/classes/interface_optional_arg_003.phpt
new file mode 100644
index 0000000..13e36d5
--- /dev/null
+++ b/tests/classes/interface_optional_arg_003.phpt
@@ -0,0 +1,17 @@
+--TEST--
+default argument value in and in implementing class with interface in included file
+--FILE--
+<?php
+include 'interface_optional_arg_003.inc';
+
+class C implements I {
+ function f($a = 2) {
+ var_dump($a);
+ }
+}
+
+$c = new C;
+$c->f();
+?>
+--EXPECTF--
+int(2) \ No newline at end of file
diff --git a/tests/classes/interfaces_001.phpt b/tests/classes/interfaces_001.phpt
new file mode 100644
index 0000000..41e1f67
--- /dev/null
+++ b/tests/classes/interfaces_001.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 interfaces
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface Throwable {
+ public function getMessage();
+}
+
+class Exception_foo implements Throwable {
+ public $foo = "foo";
+
+ public function getMessage() {
+ return $this->foo;
+ }
+}
+
+$foo = new Exception_foo;
+echo $foo->getMessage() . "\n";
+
+?>
+--EXPECT--
+foo
+
diff --git a/tests/classes/interfaces_002.phpt b/tests/classes/interfaces_002.phpt
new file mode 100644
index 0000000..d26b534
--- /dev/null
+++ b/tests/classes/interfaces_002.phpt
@@ -0,0 +1,29 @@
+--TEST--
+ZE2 interface with an unimplemented method
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface Throwable {
+ public function getMessage();
+ public function getErrno();
+}
+
+class Exception_foo implements Throwable {
+ public $foo = "foo";
+
+ public function getMessage() {
+ return $this->foo;
+ }
+}
+
+// this should die -- Exception class must be abstract...
+$foo = new Exception_foo;
+echo "Message: " . $foo->getMessage() . "\n";
+
+?>
+===DONE===
+--EXPECTF--
+
+Fatal error: Class Exception_foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Throwable::getErrno) in %s on line %d
diff --git a/tests/classes/interfaces_003.phpt b/tests/classes/interfaces_003.phpt
new file mode 100644
index 0000000..f9ab92b
--- /dev/null
+++ b/tests/classes/interfaces_003.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 interface and __construct
+--FILE--
+<?php
+
+class MyObject {}
+
+interface MyInterface
+{
+ public function __construct(MyObject $o);
+}
+
+class MyTestClass implements MyInterface
+{
+ public function __construct(MyObject $o)
+ {
+ }
+}
+
+$obj = new MyTestClass;
+
+?>
+===DONE===
+--EXPECTF--
+
+Catchable fatal error: Argument 1 passed to MyTestClass::__construct() must be an instance of MyObject, none given, called in %sinterfaces_003.php on line %d
diff --git a/tests/classes/iterators_001.phpt b/tests/classes/iterators_001.phpt
new file mode 100644
index 0000000..02e3610
--- /dev/null
+++ b/tests/classes/iterators_001.phpt
@@ -0,0 +1,200 @@
+--TEST--
+ZE2 iterators and foreach
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class c_iter implements Iterator {
+
+ private $obj;
+ private $num = 0;
+
+ function __construct($obj) {
+ echo __METHOD__ . "\n";
+ $this->num = 0;
+ $this->obj = $obj;
+ }
+ function rewind() {
+ }
+ function valid() {
+ $more = $this->num < $this->obj->max;
+ echo __METHOD__ . ' = ' .($more ? 'true' : 'false') . "\n";
+ return $more;
+ }
+ function current() {
+ echo __METHOD__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __METHOD__ . "\n";
+ $this->num++;
+ }
+ function key() {
+ echo __METHOD__ . "\n";
+ switch($this->num) {
+ case 0: return "1st";
+ case 1: return "2nd";
+ case 2: return "3rd";
+ default: return "???";
+ }
+ }
+}
+
+class c implements IteratorAggregate {
+
+ public $max = 3;
+
+ function getIterator() {
+ echo __METHOD__ . "\n";
+ return new c_iter($this);
+ }
+}
+
+echo "===Array===\n";
+
+$a = array(0,1,2);
+foreach($a as $v) {
+ echo "array:$v\n";
+}
+
+echo "===Manual===\n";
+$t = new c();
+for ($iter = $t->getIterator(); $iter->valid(); $iter->next()) {
+ echo $iter->current() . "\n";
+}
+
+echo "===foreach/std===\n";
+foreach($t as $v) {
+ echo "object:$v\n";
+}
+
+echo "===foreach/rec===\n";
+foreach($t as $v) {
+ foreach($t as $w) {
+ echo "double:$v:$w\n";
+ }
+}
+
+echo "===foreach/key===\n";
+foreach($t as $i => $v) {
+ echo "object:$i=>$v\n";
+}
+
+print "Done\n";
+exit(0);
+?>
+--EXPECT--
+===Array===
+array:0
+array:1
+array:2
+===Manual===
+c::getIterator
+c_iter::__construct
+c_iter::valid = true
+c_iter::current
+0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+1
+c_iter::next
+c_iter::valid = true
+c_iter::current
+2
+c_iter::next
+c_iter::valid = false
+===foreach/std===
+c::getIterator
+c_iter::__construct
+c_iter::valid = true
+c_iter::current
+object:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+object:1
+c_iter::next
+c_iter::valid = true
+c_iter::current
+object:2
+c_iter::next
+c_iter::valid = false
+===foreach/rec===
+c::getIterator
+c_iter::__construct
+c_iter::valid = true
+c_iter::current
+c::getIterator
+c_iter::__construct
+c_iter::valid = true
+c_iter::current
+double:0:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+double:0:1
+c_iter::next
+c_iter::valid = true
+c_iter::current
+double:0:2
+c_iter::next
+c_iter::valid = false
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c::getIterator
+c_iter::__construct
+c_iter::valid = true
+c_iter::current
+double:1:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+double:1:1
+c_iter::next
+c_iter::valid = true
+c_iter::current
+double:1:2
+c_iter::next
+c_iter::valid = false
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c::getIterator
+c_iter::__construct
+c_iter::valid = true
+c_iter::current
+double:2:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+double:2:1
+c_iter::next
+c_iter::valid = true
+c_iter::current
+double:2:2
+c_iter::next
+c_iter::valid = false
+c_iter::next
+c_iter::valid = false
+===foreach/key===
+c::getIterator
+c_iter::__construct
+c_iter::valid = true
+c_iter::current
+c_iter::key
+object:1st=>0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c_iter::key
+object:2nd=>1
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c_iter::key
+object:3rd=>2
+c_iter::next
+c_iter::valid = false
+Done
diff --git a/tests/classes/iterators_002.phpt b/tests/classes/iterators_002.phpt
new file mode 100644
index 0000000..4a58be0
--- /dev/null
+++ b/tests/classes/iterators_002.phpt
@@ -0,0 +1,113 @@
+--TEST--
+ZE2 iterators and break
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class c_iter implements Iterator {
+
+ private $obj;
+ private $num = 0;
+
+ function __construct($obj) {
+ echo __METHOD__ . "\n";
+ $this->obj = $obj;
+ }
+ function rewind() {
+ echo __METHOD__ . "\n";
+ $this->num = 0;
+ }
+ function valid() {
+ $more = $this->num < $this->obj->max;
+ echo __METHOD__ . ' = ' .($more ? 'true' : 'false') . "\n";
+ return $more;
+ }
+ function current() {
+ echo __METHOD__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __METHOD__ . "\n";
+ $this->num++;
+ }
+ function key() {
+ echo __METHOD__ . "\n";
+ switch($this->num) {
+ case 0: return "1st";
+ case 1: return "2nd";
+ case 2: return "3rd";
+ default: return "???";
+ }
+ }
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+class c implements IteratorAggregate {
+
+ public $max = 3;
+
+ function getIterator() {
+ echo __METHOD__ . "\n";
+ return new c_iter($this);
+ }
+ function __destruct() {
+ echo __METHOD__ . "\n";
+ }
+}
+
+$t = new c();
+
+foreach($t as $k => $v) {
+ foreach($t as $w) {
+ echo "double:$v:$w\n";
+ break;
+ }
+}
+
+unset($t);
+
+print "Done\n";
+?>
+--EXPECT--
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+c_iter::key
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:0:0
+c_iter::__destruct
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c_iter::key
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:1:0
+c_iter::__destruct
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c_iter::key
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:2:0
+c_iter::__destruct
+c_iter::next
+c_iter::valid = false
+c_iter::__destruct
+c::__destruct
+Done
diff --git a/tests/classes/iterators_003.phpt b/tests/classes/iterators_003.phpt
new file mode 100644
index 0000000..42695db
--- /dev/null
+++ b/tests/classes/iterators_003.phpt
@@ -0,0 +1,115 @@
+--TEST--
+ZE2 iterators and break
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class c_iter implements Iterator {
+
+ private $obj;
+ private $num = 0;
+
+ function __construct($obj) {
+ echo __METHOD__ . "\n";
+ $this->obj = $obj;
+ }
+ function rewind() {
+ echo __METHOD__ . "\n";
+ }
+ function valid() {
+ $more = $this->num < $this->obj->max;
+ echo __METHOD__ . ' = ' .($more ? 'true' : 'false') . "\n";
+ return $more;
+ }
+ function current() {
+ echo __METHOD__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __METHOD__ . "\n";
+ $this->num++;
+ }
+ function key() {
+ return $this->num;
+ }
+}
+
+class c implements IteratorAggregate {
+
+ public $max = 4;
+
+ function getIterator() {
+ echo __METHOD__ . "\n";
+ return new c_iter($this);
+ }
+}
+
+$t = new c();
+
+foreach($t as $v) {
+ if ($v == 0) {
+ echo "continue outer\n";
+ continue;
+ }
+ foreach($t as $w) {
+ if ($w == 1) {
+ echo "continue inner\n";
+ continue;
+ }
+ if ($w == 2) {
+ echo "break inner\n";
+ break;
+ }
+ echo "double:$v:$w\n";
+ }
+ if ($v == 2) {
+ echo "break outer\n";
+ break;
+ }
+}
+
+print "Done\n";
+?>
+--EXPECT--
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+continue outer
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:1:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+continue inner
+c_iter::next
+c_iter::valid = true
+c_iter::current
+break inner
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:2:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+continue inner
+c_iter::next
+c_iter::valid = true
+c_iter::current
+break inner
+break outer
+Done
diff --git a/tests/classes/iterators_004.phpt b/tests/classes/iterators_004.phpt
new file mode 100644
index 0000000..3fe0527
--- /dev/null
+++ b/tests/classes/iterators_004.phpt
@@ -0,0 +1,61 @@
+--TEST--
+ZE2 iterators must be implemented
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+echo "1st try\n";
+
+class c1 {}
+
+$obj = new c1();
+
+foreach($obj as $w) {
+ echo "object:$w\n";
+}
+
+echo "2nd try\n";
+
+class c2 {
+
+ public $max = 3;
+ public $num = 0;
+
+ function current() {
+ echo __METHOD__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __METHOD__ . "\n";
+ $this->num++;
+ }
+ function valid() {
+ echo __METHOD__ . "\n";
+ return $this->num < $this->max;
+ }
+ function key() {
+ echo __METHOD__ . "\n";
+ switch($this->num) {
+ case 0: return "1st";
+ case 1: return "2nd";
+ case 2: return "3rd";
+ default: return "???";
+ }
+ }
+}
+
+$obj = new c2();
+
+foreach($obj as $v => $w) {
+ echo "object:$v=>$w\n";
+}
+
+print "Done\n";
+?>
+--EXPECTF--
+1st try
+2nd try
+object:max=>3
+object:num=>0
+Done
diff --git a/tests/classes/iterators_005.phpt b/tests/classes/iterators_005.phpt
new file mode 100644
index 0000000..005deb9
--- /dev/null
+++ b/tests/classes/iterators_005.phpt
@@ -0,0 +1,19 @@
+--TEST--
+ZE2 iterators cannot implement Traversable alone
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class test implements Traversable {
+}
+
+$obj = new test;
+
+foreach($obj as $v);
+
+print "Done\n";
+/* the error doesn't show the filename but 'Unknown' */
+?>
+--EXPECTF--
+Fatal error: Class test must implement interface Traversable as part of either Iterator or IteratorAggregate in %s on line %d
diff --git a/tests/classes/iterators_006.phpt b/tests/classes/iterators_006.phpt
new file mode 100644
index 0000000..47fa690
--- /dev/null
+++ b/tests/classes/iterators_006.phpt
@@ -0,0 +1,87 @@
+--TEST--
+ZE2 iterators and array wrapping
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 is needed'); ?>
+--FILE--
+<?php
+
+class ai implements Iterator {
+
+ private $array;
+
+ function __construct() {
+ $this->array = array('foo', 'bar', 'baz');
+ }
+
+ function rewind() {
+ reset($this->array);
+ $this->next();
+ }
+
+ function valid() {
+ return $this->key !== NULL;
+ }
+
+ function key() {
+ return $this->key;
+ }
+
+ function current() {
+ return $this->current;
+ }
+
+ function next() {
+ list($this->key, $this->current) = each($this->array);
+// list($key, $current) = each($this->array);
+// $this->key = $key;
+// $this->current = $current;
+ }
+}
+
+class a implements IteratorAggregate {
+
+ public function getIterator() {
+ return new ai();
+ }
+}
+
+$array = new a();
+
+foreach ($array as $property => $value) {
+ print "$property: $value\n";
+}
+
+#$array = $array->getIterator();
+#$array->rewind();
+#$array->valid();
+#var_dump($array->key());
+#var_dump($array->current());
+echo "===2nd===\n";
+
+$array = new ai();
+
+foreach ($array as $property => $value) {
+ print "$property: $value\n";
+}
+
+echo "===3rd===\n";
+
+foreach ($array as $property => $value) {
+ print "$property: $value\n";
+}
+
+?>
+===DONE===
+--EXPECT--
+0: foo
+1: bar
+2: baz
+===2nd===
+0: foo
+1: bar
+2: baz
+===3rd===
+0: foo
+1: bar
+2: baz
+===DONE=== \ No newline at end of file
diff --git a/tests/classes/iterators_007.phpt b/tests/classes/iterators_007.phpt
new file mode 100644
index 0000000..f2638b3
--- /dev/null
+++ b/tests/classes/iterators_007.phpt
@@ -0,0 +1,43 @@
+--TEST--
+ZE2 iterators and exceptions
+--FILE--
+<?php
+class Test implements Iterator
+{
+ public $arr = array(1, 2, 3);
+ public $x = 0;
+
+ public function rewind() { if ($this->x == 0) throw new Exception(__METHOD__); reset($this->arr); }
+ public function current() { if ($this->x == 1) throw new Exception(__METHOD__); return current($this->arr); }
+ public function key() { if ($this->x == 2) throw new Exception(__METHOD__); return key($this->arr); }
+ public function next() { if ($this->x == 3) throw new Exception(__METHOD__); next($this->arr); }
+ public function valid() { if ($this->x == 4) throw new Exception(__METHOD__); return (key($this->arr) !== NULL); }
+}
+
+$t = new Test();
+
+while($t->x < 5)
+{
+ try
+ {
+ foreach($t as $k => $v)
+ {
+ echo "Current\n";
+ }
+ }
+ catch(Exception $e)
+ {
+ echo "Caught in " . $e->getMessage() . "()\n";
+ }
+ $t->x++;
+}
+?>
+===DONE===
+--EXPECT--
+Caught in Test::rewind()
+Caught in Test::current()
+Caught in Test::key()
+Current
+Caught in Test::next()
+Caught in Test::valid()
+===DONE===
diff --git a/tests/classes/iterators_008.phpt b/tests/classes/iterators_008.phpt
new file mode 100644
index 0000000..22e6dc8
--- /dev/null
+++ b/tests/classes/iterators_008.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Ensure plain userspace superclass does not override special iterator behaviour on child class.
+--FILE--
+<?php
+Class C {}
+
+class D extends C implements Iterator {
+
+ private $counter = 2;
+
+ public function valid() {
+ echo __METHOD__ . "($this->counter)\n";
+ return $this->counter;
+ }
+
+ public function next() {
+ $this->counter--;
+ echo __METHOD__ . "($this->counter)\n";
+ }
+
+ public function rewind() {
+ echo __METHOD__ . "($this->counter)\n";
+ }
+
+ public function current() {
+ echo __METHOD__ . "($this->counter)\n";
+ }
+
+ public function key() {
+ echo __METHOD__ . "($this->counter)\n";
+ }
+
+}
+
+foreach (new D as $x) {}
+?>
+--EXPECTF--
+D::rewind(2)
+D::valid(2)
+D::current(2)
+D::next(1)
+D::valid(1)
+D::current(1)
+D::next(0)
+D::valid(0) \ No newline at end of file
diff --git a/tests/classes/method_call_variation_001.phpt b/tests/classes/method_call_variation_001.phpt
new file mode 100644
index 0000000..dd43cfd
--- /dev/null
+++ b/tests/classes/method_call_variation_001.phpt
@@ -0,0 +1,37 @@
+--TEST--
+In $a->$b[Y](), $b[Y] represents a method name on $a. But in $a->X[Y](), $a->X[Y] represents a global function name.
+--FILE--
+<?php
+ class C
+ {
+ function foo($a, $b)
+ {
+ echo "Called C::foo($a, $b)\n";
+ }
+ }
+
+ $c = new C;
+
+ $functions[0] = 'foo';
+ $functions[1][2][3][4] = 'foo';
+
+ $c->$functions[0](1, 2);
+ $c->$functions[1][2][3][4](3, 4);
+
+
+ function foo($a, $b)
+ {
+ echo "Called global foo($a, $b)\n";
+ }
+
+ $c->functions[0] = 'foo';
+ $c->functions[1][2][3][4] = 'foo';
+
+ $c->functions[0](5, 6);
+ $c->functions[1][2][3][4](7, 8);
+?>
+--EXPECTF--
+Called C::foo(1, 2)
+Called C::foo(3, 4)
+Called global foo(5, 6)
+Called global foo(7, 8)
diff --git a/tests/classes/method_override_optional_arg_001.phpt b/tests/classes/method_override_optional_arg_001.phpt
new file mode 100644
index 0000000..333c29d
--- /dev/null
+++ b/tests/classes/method_override_optional_arg_001.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Method override allows optional default argument
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class A {
+ function foo($arg1 = 1) {
+ }
+}
+
+class B extends A {
+ function foo($arg1 = 2, $arg2 = 3) {
+ var_dump($arg1);
+ var_dump($arg2);
+ }
+}
+
+class C extends A {
+ function foo() {
+ }
+}
+
+$b = new B();
+
+$b->foo(1);
+
+?>
+--EXPECTF--
+Strict Standards: Declaration of C::foo() should be compatible with A::foo($arg1 = 1) in %s on line %d
+int(1)
+int(3)
diff --git a/tests/classes/method_override_optional_arg_002.phpt b/tests/classes/method_override_optional_arg_002.phpt
new file mode 100644
index 0000000..669a8ca
--- /dev/null
+++ b/tests/classes/method_override_optional_arg_002.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Omitting optional arg in method inherited from abstract class
+--FILE--
+<?php
+
+abstract class A {
+ function foo($arg = 1) {}
+}
+
+class B extends A {
+ function foo() {
+ echo "foo\n";
+ }
+}
+
+$b = new B();
+$b->foo();
+
+?>
+--EXPECTF--
+Strict Standards: Declaration of B::foo() should be compatible with A::foo($arg = 1) in %s on line %d
+foo
diff --git a/tests/classes/new_001.phpt b/tests/classes/new_001.phpt
new file mode 100644
index 0000000..ee7d352
--- /dev/null
+++ b/tests/classes/new_001.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Confirm difference between assigning new directly and by reference.
+--INI--
+error_reporting=E_ALL | E_DEPRECATED
+--FILE--
+<?php
+ echo "Compile-time strict error message should precede this.\n";
+
+ class Inc
+ {
+ private static $counter = 0;
+ function __construct()
+ {
+ $this->id = ++Inc::$counter;
+ }
+ }
+
+ $f = new Inc();
+ $k =& $f;
+ echo "\$f initially points to the first object:\n";
+ var_dump($f);
+
+ echo "Assigning new object directly to \$k affects \$f:\n";
+ $k = new Inc();
+ var_dump($f);
+
+ echo "Assigning new object by ref to \$k removes it from \$f's reference set, so \$f is unchanged:\n";
+ $k =& new Inc();
+ var_dump($f);
+?>
+--EXPECTF--
+Deprecated: Assigning the return value of new by reference is deprecated in %s on line 23
+Compile-time strict error message should precede this.
+$f initially points to the first object:
+object(Inc)#%d (1) {
+ ["id"]=>
+ int(1)
+}
+Assigning new object directly to $k affects $f:
+object(Inc)#%d (1) {
+ ["id"]=>
+ int(2)
+}
+Assigning new object by ref to $k removes it from $f's reference set, so $f is unchanged:
+object(Inc)#%d (1) {
+ ["id"]=>
+ int(2)
+}
diff --git a/tests/classes/object_reference_001.phpt b/tests/classes/object_reference_001.phpt
new file mode 100644
index 0000000..74acb5d
--- /dev/null
+++ b/tests/classes/object_reference_001.phpt
@@ -0,0 +1,27 @@
+--TEST--
+ZE2 object references
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Foo {
+ public $name;
+
+ function Foo() {
+ $this->name = "I'm Foo!\n";
+ }
+}
+
+$foo = new Foo;
+echo $foo->name;
+$bar = $foo;
+$bar->name = "I'm Bar!\n";
+
+// In ZE1, we would expect "I'm Foo!"
+echo $foo->name;
+
+?>
+--EXPECT--
+I'm Foo!
+I'm Bar!
diff --git a/tests/classes/private_001.phpt b/tests/classes/private_001.phpt
new file mode 100644
index 0000000..310b9c6
--- /dev/null
+++ b/tests/classes/private_001.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 A private method can only be called inside the class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ private static function show() {
+ echo "Call show()\n";
+ }
+
+ public static function do_show() {
+ pass::show();
+ }
+}
+
+pass::do_show();
+pass::show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call show()
+
+Fatal error: Call to private method pass::show() from context '' in %s on line %d
diff --git a/tests/classes/private_002.phpt b/tests/classes/private_002.phpt
new file mode 100644
index 0000000..258fd3a
--- /dev/null
+++ b/tests/classes/private_002.phpt
@@ -0,0 +1,35 @@
+--TEST--
+ZE2 A private method cannot be called in another class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ private static function show() {
+ echo "Call pass::show()\n";
+ }
+
+ public static function do_show() {
+ pass::show();
+ }
+}
+
+pass::do_show();
+
+class fail {
+ public static function show() {
+ echo "Call fail::show()\n";
+ pass::show();
+ }
+}
+
+fail::show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call pass::show()
+Call fail::show()
+
+Fatal error: Call to private method pass::show() from context 'fail' in %s on line %d
diff --git a/tests/classes/private_003.phpt b/tests/classes/private_003.phpt
new file mode 100644
index 0000000..716efbc
--- /dev/null
+++ b/tests/classes/private_003.phpt
@@ -0,0 +1,36 @@
+--TEST--
+ZE2 A private method cannot be called in a derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+ini_set("error_reporting",2039);
+class pass {
+ private static function show() {
+ echo "Call show()\n";
+ }
+
+ protected static function good() {
+ pass::show();
+ }
+}
+
+class fail extends pass {
+ static function ok() {
+ pass::good();
+ }
+
+ static function not_ok() {
+ pass::show();
+ }
+}
+
+fail::ok();
+fail::not_ok(); // calling a private function
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call show()
+
+Fatal error: Call to private method pass::show() from context 'fail' in %s on line %d
diff --git a/tests/classes/private_003b.phpt b/tests/classes/private_003b.phpt
new file mode 100644
index 0000000..780b2e6
--- /dev/null
+++ b/tests/classes/private_003b.phpt
@@ -0,0 +1,37 @@
+--TEST--
+ZE2 A private method cannot be called in a derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ private function show() {
+ echo "Call show()\n";
+ }
+
+ protected function good() {
+ $this->show();
+ }
+}
+
+class fail extends pass {
+ public function ok() {
+ $this->good();
+ }
+
+ public function not_ok() {
+ $this->show();
+ }
+}
+
+$t = new fail();
+$t->ok();
+$t->not_ok(); // calling a private function
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call show()
+
+Fatal error: Call to private method pass::show() from context 'fail' in %s on line %d
diff --git a/tests/classes/private_004.phpt b/tests/classes/private_004.phpt
new file mode 100644
index 0000000..027434a
--- /dev/null
+++ b/tests/classes/private_004.phpt
@@ -0,0 +1,32 @@
+--TEST--
+ZE2 A private method cannot be called in a derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ private static function show() {
+ echo "Call show()\n";
+ }
+
+ public static function do_show() {
+ pass::show();
+ }
+}
+
+class fail extends pass {
+ static function do_show() {
+ fail::show();
+ }
+}
+
+pass::do_show();
+fail::do_show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call show()
+
+Fatal error: Call to private method pass::show() from context 'fail' in %s on line %d
diff --git a/tests/classes/private_004b.phpt b/tests/classes/private_004b.phpt
new file mode 100644
index 0000000..ea3fe61
--- /dev/null
+++ b/tests/classes/private_004b.phpt
@@ -0,0 +1,35 @@
+--TEST--
+ZE2 A private method cannot be called in a derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ private function show() {
+ echo "Call show()\n";
+ }
+
+ public function do_show() {
+ $this->show();
+ }
+}
+
+class fail extends pass {
+ function do_show() {
+ $this->show();
+ }
+}
+
+$t = new pass();
+$t->do_show();
+
+$t2 = new fail();
+$t2->do_show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call show()
+
+Fatal error: Call to private method pass::show() from context 'fail' in %s on line %d \ No newline at end of file
diff --git a/tests/classes/private_005.phpt b/tests/classes/private_005.phpt
new file mode 100644
index 0000000..49b2bee
--- /dev/null
+++ b/tests/classes/private_005.phpt
@@ -0,0 +1,32 @@
+--TEST--
+ZE2 A private method cannot be called in a derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ private static function show() {
+ echo "Call show()\n";
+ }
+
+ public static function do_show() {
+ pass::show();
+ }
+}
+
+class fail extends pass {
+ static function do_show() {
+ pass::show();
+ }
+}
+
+pass::do_show();
+fail::do_show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call show()
+
+Fatal error: Call to private method pass::show() from context 'fail' in %s on line %d
diff --git a/tests/classes/private_005b.phpt b/tests/classes/private_005b.phpt
new file mode 100644
index 0000000..ea3fe61
--- /dev/null
+++ b/tests/classes/private_005b.phpt
@@ -0,0 +1,35 @@
+--TEST--
+ZE2 A private method cannot be called in a derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ private function show() {
+ echo "Call show()\n";
+ }
+
+ public function do_show() {
+ $this->show();
+ }
+}
+
+class fail extends pass {
+ function do_show() {
+ $this->show();
+ }
+}
+
+$t = new pass();
+$t->do_show();
+
+$t2 = new fail();
+$t2->do_show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call show()
+
+Fatal error: Call to private method pass::show() from context 'fail' in %s on line %d \ No newline at end of file
diff --git a/tests/classes/private_006.phpt b/tests/classes/private_006.phpt
new file mode 100644
index 0000000..0bb2b3f
--- /dev/null
+++ b/tests/classes/private_006.phpt
@@ -0,0 +1,41 @@
+--TEST--
+ZE2 A private method can be overwritten in a second derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+class first {
+ private static function show() {
+ echo "Call show()\n";
+ }
+
+ public static function do_show() {
+ first::show();
+ }
+}
+
+first::do_show();
+
+class second extends first {
+}
+
+second::do_show();
+
+class third extends second {
+}
+
+third::do_show();
+
+class fail extends third {
+ static function show() { // cannot be redeclared
+ echo "Call show()\n";
+ }
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Call show()
+Call show()
+Call show()
+Done
diff --git a/tests/classes/private_006b.phpt b/tests/classes/private_006b.phpt
new file mode 100644
index 0000000..950f16a
--- /dev/null
+++ b/tests/classes/private_006b.phpt
@@ -0,0 +1,41 @@
+--TEST--
+ZE2 A private method can be overwritten in a second derived class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class first {
+ private function show() {
+ echo "Call show()\n";
+ }
+
+ public function do_show() {
+ $this->show();
+ }
+}
+
+$t1 = new first();
+$t1->do_show();
+
+class second extends first {
+}
+
+//$t2 = new second();
+//$t2->do_show();
+
+class third extends second {
+ private function show() {
+ echo "Call show()\n";
+ }
+}
+
+$t3 = new third();
+$t3->do_show();
+
+echo "Done\n";
+?>
+--EXPECTF--
+Call show()
+Call show()
+Done \ No newline at end of file
diff --git a/tests/classes/private_007.phpt b/tests/classes/private_007.phpt
new file mode 100644
index 0000000..73a38c4
--- /dev/null
+++ b/tests/classes/private_007.phpt
@@ -0,0 +1,30 @@
+--TEST--
+ZE2 A derived class does not know about privates of ancestors
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Bar {
+ public static function pub() {
+ Bar::priv();
+ }
+ private static function priv() {
+ echo "Bar::priv()\n";
+ }
+}
+class Foo extends Bar {
+ public static function priv() {
+ echo "Foo::priv()\n";
+ }
+}
+
+Foo::pub();
+Foo::priv();
+
+echo "Done\n";
+?>
+--EXPECTF--
+Bar::priv()
+Foo::priv()
+Done
diff --git a/tests/classes/private_007b.phpt b/tests/classes/private_007b.phpt
new file mode 100644
index 0000000..02ddc25
--- /dev/null
+++ b/tests/classes/private_007b.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 A derived class does not know about privates of ancestors
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Bar {
+ public function pub() {
+ $this->priv();
+ }
+ private function priv() {
+ echo "Bar::priv()\n";
+ }
+}
+class Foo extends Bar {
+ public function priv() {
+ echo "Foo::priv()\n";
+ }
+}
+
+$obj = new Foo();
+$obj->pub();
+$obj->priv();
+
+echo "Done\n";
+?>
+--EXPECTF--
+Bar::priv()
+Foo::priv()
+Done
diff --git a/tests/classes/private_members.phpt b/tests/classes/private_members.phpt
new file mode 100644
index 0000000..a8ef9ab
--- /dev/null
+++ b/tests/classes/private_members.phpt
@@ -0,0 +1,103 @@
+--TEST--
+ZE2 A private member is
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class base
+{
+ private $member;
+
+ function __construct()
+ {
+ echo __METHOD__ . "(begin)\n";
+ $this->member = 'base::member';
+ $this->test();
+ echo __METHOD__ . "(end)\n";
+ }
+
+ function test()
+ {
+ echo __METHOD__ . "\n";
+ print_r($this);
+ }
+}
+
+class derived extends base
+{
+ public $member = 'derived::member (default)';
+
+ function __construct()
+ {
+ echo __METHOD__ . "(begin)\n";
+ parent::__construct();
+ parent::test();
+ $this->test();
+ $this->member = 'derived::member';
+ echo __METHOD__ . "(end)\n";
+ }
+
+ function test()
+ {
+ parent::test();
+ echo __METHOD__ . "\n";
+ print_r($this);
+ }
+}
+
+$t = new derived;
+$t->test();
+unset($t);
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+derived::__construct(begin)
+base::__construct(begin)
+base::test
+derived Object
+(
+ [member] => derived::member (default)
+ [member:base:private] => base::member
+)
+derived::test
+derived Object
+(
+ [member] => derived::member (default)
+ [member:base:private] => base::member
+)
+base::__construct(end)
+base::test
+derived Object
+(
+ [member] => derived::member (default)
+ [member:base:private] => base::member
+)
+base::test
+derived Object
+(
+ [member] => derived::member (default)
+ [member:base:private] => base::member
+)
+derived::test
+derived Object
+(
+ [member] => derived::member (default)
+ [member:base:private] => base::member
+)
+derived::__construct(end)
+base::test
+derived Object
+(
+ [member] => derived::member
+ [member:base:private] => base::member
+)
+derived::test
+derived Object
+(
+ [member] => derived::member
+ [member:base:private] => base::member
+)
+Done
diff --git a/tests/classes/private_redeclare.phpt b/tests/classes/private_redeclare.phpt
new file mode 100644
index 0000000..e3061f1
--- /dev/null
+++ b/tests/classes/private_redeclare.phpt
@@ -0,0 +1,38 @@
+--TEST--
+ZE2 A derived class does not know anything about inherited private methods
+--FILE--
+<?php
+class base {
+ private function show() {
+ echo "base\n";
+ }
+ function test() {
+ $this->show();
+ }
+}
+
+$t = new base();
+$t->test();
+
+class derived extends base {
+ function show() {
+ echo "derived\n";
+ }
+ function test() {
+ echo "test\n";
+ $this->show();
+ parent::test();
+ parent::show();
+ }
+}
+
+$t = new derived();
+$t->test();
+?>
+--EXPECTF--
+base
+test
+derived
+base
+
+Fatal error: Call to private method base::show() from context 'derived' in %s on line %d
diff --git a/tests/classes/property_override_privateStatic_private.phpt b/tests/classes/property_override_privateStatic_private.phpt
new file mode 100644
index 0000000..ddd2e5d
--- /dev/null
+++ b/tests/classes/property_override_privateStatic_private.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited private static property as private.
+--FILE--
+<?php
+ class A
+ {
+ private static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p
diff --git a/tests/classes/property_override_privateStatic_privateStatic.phpt b/tests/classes/property_override_privateStatic_privateStatic.phpt
new file mode 100644
index 0000000..d7d645f
--- /dev/null
+++ b/tests/classes/property_override_privateStatic_privateStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited private static property as private static.
+--FILE--
+<?php
+ class A
+ {
+ private static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p (static)
diff --git a/tests/classes/property_override_privateStatic_protected.phpt b/tests/classes/property_override_privateStatic_protected.phpt
new file mode 100644
index 0000000..d473216
--- /dev/null
+++ b/tests/classes/property_override_privateStatic_protected.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited private static property as protected.
+--FILE--
+<?php
+ class A
+ {
+ private static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p
diff --git a/tests/classes/property_override_privateStatic_protectedStatic.phpt b/tests/classes/property_override_privateStatic_protectedStatic.phpt
new file mode 100644
index 0000000..169ff9a
--- /dev/null
+++ b/tests/classes/property_override_privateStatic_protectedStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited private static property as protected static.
+--FILE--
+<?php
+ class A
+ {
+ private static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p (static)
diff --git a/tests/classes/property_override_privateStatic_public.phpt b/tests/classes/property_override_privateStatic_public.phpt
new file mode 100644
index 0000000..033eb75
--- /dev/null
+++ b/tests/classes/property_override_privateStatic_public.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited private static property as public.
+--FILE--
+<?php
+ class A
+ {
+ private static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p
diff --git a/tests/classes/property_override_privateStatic_publicStatic.phpt b/tests/classes/property_override_privateStatic_publicStatic.phpt
new file mode 100644
index 0000000..5f2b6bf
--- /dev/null
+++ b/tests/classes/property_override_privateStatic_publicStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited private static property as public static.
+--FILE--
+<?php
+ class A
+ {
+ private static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p (static)
diff --git a/tests/classes/property_override_private_private.phpt b/tests/classes/property_override_private_private.phpt
new file mode 100644
index 0000000..2b263ee
--- /dev/null
+++ b/tests/classes/property_override_private_private.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited private property as private.
+--FILE--
+<?php
+ class A
+ {
+ private $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p
+A::p
+B::p
diff --git a/tests/classes/property_override_private_privateStatic.phpt b/tests/classes/property_override_private_privateStatic.phpt
new file mode 100644
index 0000000..606ed21
--- /dev/null
+++ b/tests/classes/property_override_private_privateStatic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited private property as private static.
+--FILE--
+<?php
+ class A
+ {
+ private $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p
+A::p
+B::p (static)
diff --git a/tests/classes/property_override_private_protected.phpt b/tests/classes/property_override_private_protected.phpt
new file mode 100644
index 0000000..b84ed67
--- /dev/null
+++ b/tests/classes/property_override_private_protected.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited private property as protected.
+--FILE--
+<?php
+ class A
+ {
+ private $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p
+A::p
+B::p
diff --git a/tests/classes/property_override_private_protectedStatic.phpt b/tests/classes/property_override_private_protectedStatic.phpt
new file mode 100644
index 0000000..1bb303d
--- /dev/null
+++ b/tests/classes/property_override_private_protectedStatic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited private property as protected static.
+--FILE--
+<?php
+ class A
+ {
+ private $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p
+A::p
+B::p (static)
diff --git a/tests/classes/property_override_private_public.phpt b/tests/classes/property_override_private_public.phpt
new file mode 100644
index 0000000..badbe91
--- /dev/null
+++ b/tests/classes/property_override_private_public.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited private property as public.
+--FILE--
+<?php
+ class A
+ {
+ private $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p
+A::p
+B::p
diff --git a/tests/classes/property_override_private_publicStatic.phpt b/tests/classes/property_override_private_publicStatic.phpt
new file mode 100644
index 0000000..9fc58ec
--- /dev/null
+++ b/tests/classes/property_override_private_publicStatic.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited private property as public static.
+--FILE--
+<?php
+ class A
+ {
+ private $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p
+A::p
+B::p (static)
diff --git a/tests/classes/property_override_protectedStatic_private.phpt b/tests/classes/property_override_protectedStatic_private.phpt
new file mode 100644
index 0000000..18e9c78
--- /dev/null
+++ b/tests/classes/property_override_protectedStatic_private.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected static property as private.
+--FILE--
+<?php
+ class A
+ {
+ protected static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare static A::$p as non static B::$p in %s on line 18
+
diff --git a/tests/classes/property_override_protectedStatic_privateStatic.phpt b/tests/classes/property_override_protectedStatic_privateStatic.phpt
new file mode 100644
index 0000000..6886210
--- /dev/null
+++ b/tests/classes/property_override_protectedStatic_privateStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited protected static property as private static.
+--FILE--
+<?php
+ class A
+ {
+ protected static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Access level to B::$p must be protected (as in class A) or weaker in %s on line 18
+
diff --git a/tests/classes/property_override_protectedStatic_protected.phpt b/tests/classes/property_override_protectedStatic_protected.phpt
new file mode 100644
index 0000000..0e5fdd3
--- /dev/null
+++ b/tests/classes/property_override_protectedStatic_protected.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected static property as protected.
+--FILE--
+<?php
+ class A
+ {
+ protected static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare static A::$p as non static B::$p in %s on line 18
+
diff --git a/tests/classes/property_override_protectedStatic_protectedStatic.phpt b/tests/classes/property_override_protectedStatic_protectedStatic.phpt
new file mode 100644
index 0000000..16f1100
--- /dev/null
+++ b/tests/classes/property_override_protectedStatic_protectedStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited protected static property as protected static.
+--FILE--
+<?php
+ class A
+ {
+ protected static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p (static)
diff --git a/tests/classes/property_override_protectedStatic_public.phpt b/tests/classes/property_override_protectedStatic_public.phpt
new file mode 100644
index 0000000..6303325
--- /dev/null
+++ b/tests/classes/property_override_protectedStatic_public.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected static property as public.
+--FILE--
+<?php
+ class A
+ {
+ protected static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare static A::$p as non static B::$p in %s on line 18
+
diff --git a/tests/classes/property_override_protectedStatic_publicStatic.phpt b/tests/classes/property_override_protectedStatic_publicStatic.phpt
new file mode 100644
index 0000000..e437c5f
--- /dev/null
+++ b/tests/classes/property_override_protectedStatic_publicStatic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected static property as public static.
+--FILE--
+<?php
+ class A
+ {
+ protected static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p (static)
+
diff --git a/tests/classes/property_override_protected_private.phpt b/tests/classes/property_override_protected_private.phpt
new file mode 100644
index 0000000..22cceda
--- /dev/null
+++ b/tests/classes/property_override_protected_private.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected property as private (duplicates Zend/tests/errmsg_023.phpt).
+--FILE--
+<?php
+ class A
+ {
+ protected $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Access level to B::$p must be protected (as in class A) or weaker in %s on line 18
diff --git a/tests/classes/property_override_protected_privateStatic.phpt b/tests/classes/property_override_protected_privateStatic.phpt
new file mode 100644
index 0000000..fb7102c
--- /dev/null
+++ b/tests/classes/property_override_protected_privateStatic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected property as private static.
+--FILE--
+<?php
+ class A
+ {
+ protected $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare non static A::$p as static B::$p in %s on line 18
diff --git a/tests/classes/property_override_protected_protected.phpt b/tests/classes/property_override_protected_protected.phpt
new file mode 100644
index 0000000..c4b0d43
--- /dev/null
+++ b/tests/classes/property_override_protected_protected.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited protected property as protected.
+--FILE--
+<?php
+ class A
+ {
+ protected $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p
+B::p
+B::p
diff --git a/tests/classes/property_override_protected_protectedStatic.phpt b/tests/classes/property_override_protected_protectedStatic.phpt
new file mode 100644
index 0000000..1ce4130
--- /dev/null
+++ b/tests/classes/property_override_protected_protectedStatic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected property as protected static.
+--FILE--
+<?php
+ class A
+ {
+ protected $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare non static A::$p as static B::$p in %s on line 18
diff --git a/tests/classes/property_override_protected_public.phpt b/tests/classes/property_override_protected_public.phpt
new file mode 100644
index 0000000..4702f9a
--- /dev/null
+++ b/tests/classes/property_override_protected_public.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited protected property as public.
+--FILE--
+<?php
+ class A
+ {
+ protected $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p
+B::p
+B::p
diff --git a/tests/classes/property_override_protected_publicStatic.phpt b/tests/classes/property_override_protected_publicStatic.phpt
new file mode 100644
index 0000000..8efdf5f
--- /dev/null
+++ b/tests/classes/property_override_protected_publicStatic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited protected property as public static.
+--FILE--
+<?php
+ class A
+ {
+ protected $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare non static A::$p as static B::$p in %s on line 18
diff --git a/tests/classes/property_override_publicStatic_private.phpt b/tests/classes/property_override_publicStatic_private.phpt
new file mode 100644
index 0000000..7abe92c
--- /dev/null
+++ b/tests/classes/property_override_publicStatic_private.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited public static property as private.
+--FILE--
+<?php
+ class A
+ {
+ public static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare static A::$p as non static B::$p in %s on line 18
+
diff --git a/tests/classes/property_override_publicStatic_privateStatic.phpt b/tests/classes/property_override_publicStatic_privateStatic.phpt
new file mode 100644
index 0000000..d41db6d
--- /dev/null
+++ b/tests/classes/property_override_publicStatic_privateStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited public static property as private static.
+--FILE--
+<?php
+ class A
+ {
+ public static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Access level to B::$p must be public (as in class A) in %s on line 18
+
diff --git a/tests/classes/property_override_publicStatic_protected.phpt b/tests/classes/property_override_publicStatic_protected.phpt
new file mode 100644
index 0000000..884159f
--- /dev/null
+++ b/tests/classes/property_override_publicStatic_protected.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited public static property as protected.
+--FILE--
+<?php
+ class A
+ {
+ public static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare static A::$p as non static B::$p in %s on line 18
+
diff --git a/tests/classes/property_override_publicStatic_protectedStatic.phpt b/tests/classes/property_override_publicStatic_protectedStatic.phpt
new file mode 100644
index 0000000..b022ef8
--- /dev/null
+++ b/tests/classes/property_override_publicStatic_protectedStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited public static property as protected static.
+--FILE--
+<?php
+ class A
+ {
+ public static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Access level to B::$p must be public (as in class A) in %s on line 18
+
diff --git a/tests/classes/property_override_publicStatic_public.phpt b/tests/classes/property_override_publicStatic_public.phpt
new file mode 100644
index 0000000..d099da0
--- /dev/null
+++ b/tests/classes/property_override_publicStatic_public.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited public static property as public.
+--FILE--
+<?php
+ class A
+ {
+ public static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare static A::$p as non static B::$p in %s on line 18
+
diff --git a/tests/classes/property_override_publicStatic_publicStatic.phpt b/tests/classes/property_override_publicStatic_publicStatic.phpt
new file mode 100644
index 0000000..9a86867
--- /dev/null
+++ b/tests/classes/property_override_publicStatic_publicStatic.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Redeclare inherited public static property as public static.
+--FILE--
+<?php
+ class A
+ {
+ public static $p = "A::p (static)";
+ static function showA()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ A::showA();
+
+ B::showA();
+ B::showB();
+?>
+--EXPECTF--
+A::p (static)
+A::p (static)
+B::p (static)
diff --git a/tests/classes/property_override_public_private.phpt b/tests/classes/property_override_public_private.phpt
new file mode 100644
index 0000000..c0f37ad
--- /dev/null
+++ b/tests/classes/property_override_public_private.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited public property as private.
+--FILE--
+<?php
+ class A
+ {
+ public $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Access level to B::$p must be public (as in class A) in %s on line 18
+
diff --git a/tests/classes/property_override_public_privateStatic.phpt b/tests/classes/property_override_public_privateStatic.phpt
new file mode 100644
index 0000000..36223fd
--- /dev/null
+++ b/tests/classes/property_override_public_privateStatic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited public property as private static.
+--FILE--
+<?php
+ class A
+ {
+ public $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ private static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare non static A::$p as static B::$p in %s on line 18
diff --git a/tests/classes/property_override_public_protected.phpt b/tests/classes/property_override_public_protected.phpt
new file mode 100644
index 0000000..68fdf82
--- /dev/null
+++ b/tests/classes/property_override_public_protected.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited public property as protected.
+--FILE--
+<?php
+ class A
+ {
+ public $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+
+Fatal error: Access level to B::$p must be public (as in class A) in %s on line 18
+
diff --git a/tests/classes/property_override_public_protectedStatic.phpt b/tests/classes/property_override_public_protectedStatic.phpt
new file mode 100644
index 0000000..77e7ebf
--- /dev/null
+++ b/tests/classes/property_override_public_protectedStatic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited public property as protected static.
+--FILE--
+<?php
+ class A
+ {
+ public $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ protected static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare non static A::$p as static B::$p in %s on line 18
diff --git a/tests/classes/property_override_public_public.phpt b/tests/classes/property_override_public_public.phpt
new file mode 100644
index 0000000..893fe5d
--- /dev/null
+++ b/tests/classes/property_override_public_public.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Redeclare inherited public property as public.
+--FILE--
+<?php
+ class A
+ {
+ public $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public $p = "B::p";
+ function showB()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ $b->showB();
+?>
+--EXPECTF--
+A::p
+B::p
+B::p
diff --git a/tests/classes/property_override_public_publicStatic.phpt b/tests/classes/property_override_public_publicStatic.phpt
new file mode 100644
index 0000000..725e947
--- /dev/null
+++ b/tests/classes/property_override_public_publicStatic.phpt
@@ -0,0 +1,33 @@
+--TEST--
+Redeclare inherited public property as public static.
+--FILE--
+<?php
+ class A
+ {
+ public $p = "A::p";
+ function showA()
+ {
+ echo $this->p . "\n";
+ }
+ }
+
+ class B extends A
+ {
+ public static $p = "B::p (static)";
+ static function showB()
+ {
+ echo self::$p . "\n";
+ }
+ }
+
+
+ $a = new A;
+ $a->showA();
+
+ $b = new B;
+ $b->showA();
+ B::showB();
+?>
+--EXPECTF--
+
+Fatal error: Cannot redeclare non static A::$p as static B::$p in %s on line 18
diff --git a/tests/classes/property_recreate_private.phpt b/tests/classes/property_recreate_private.phpt
new file mode 100644
index 0000000..8bcf485
--- /dev/null
+++ b/tests/classes/property_recreate_private.phpt
@@ -0,0 +1,81 @@
+--TEST--
+Unsetting and recreating private properties.
+--FILE--
+<?php
+class C {
+ private $p = 'test';
+ function unsetPrivate() {
+ unset($this->p);
+ }
+ function setPrivate() {
+ $this->p = 'changed';
+ }
+}
+
+class D extends C {
+ function setP() {
+ $this->p = 'changed in D';
+ }
+}
+
+echo "Unset and recreate a superclass's private property:\n";
+$d = new D;
+$d->unsetPrivate();
+$d->setPrivate();
+var_dump($d);
+
+echo "\nUnset superclass's private property, and recreate it as public in subclass:\n";
+$d = new D;
+$d->unsetPrivate();
+$d->setP();
+var_dump($d);
+
+echo "\nUnset superclass's private property, and recreate it as public at global scope:\n";
+$d = new D;
+$d->unsetPrivate();
+$d->p = 'this will create a public property';
+var_dump($d);
+
+
+echo "\n\nUnset and recreate a private property:\n";
+$c = new C;
+$c->unsetPrivate();
+$c->setPrivate();
+var_dump($c);
+
+echo "\nUnset a private property, and attempt to recreate at global scope (expecting failure):\n";
+$c = new C;
+$c->unsetPrivate();
+$c->p = 'this will fail';
+var_dump($c);
+?>
+==Done==
+--EXPECTF--
+Unset and recreate a superclass's private property:
+object(D)#%d (1) {
+ [%u|b%"p":%u|b%"C":private]=>
+ %unicode|string%(7) "changed"
+}
+
+Unset superclass's private property, and recreate it as public in subclass:
+object(D)#%d (1) {
+ [%u|b%"p"]=>
+ %unicode|string%(12) "changed in D"
+}
+
+Unset superclass's private property, and recreate it as public at global scope:
+object(D)#%d (1) {
+ [%u|b%"p"]=>
+ %unicode|string%(34) "this will create a public property"
+}
+
+
+Unset and recreate a private property:
+object(C)#%d (1) {
+ [%u|b%"p":%u|b%"C":private]=>
+ %unicode|string%(7) "changed"
+}
+
+Unset a private property, and attempt to recreate at global scope (expecting failure):
+
+Fatal error: Cannot access private property C::$p in %s on line 46 \ No newline at end of file
diff --git a/tests/classes/property_recreate_protected.phpt b/tests/classes/property_recreate_protected.phpt
new file mode 100644
index 0000000..4da4de8
--- /dev/null
+++ b/tests/classes/property_recreate_protected.phpt
@@ -0,0 +1,53 @@
+--TEST--
+Unsetting and recreating protected properties.
+--FILE--
+<?php
+class C {
+ protected $p = 'test';
+ function unsetProtected() {
+ unset($this->p);
+ }
+ function setProtected() {
+ $this->p = 'changed';
+ }
+}
+
+class D extends C {
+ function setP() {
+ $this->p = 'changed in D';
+ }
+}
+
+$d = new D;
+echo "Unset and recreate a protected property from property's declaring class scope:\n";
+$d->unsetProtected();
+$d->setProtected();
+var_dump($d);
+
+echo "\nUnset and recreate a protected property from subclass:\n";
+$d = new D;
+$d->unsetProtected();
+$d->setP();
+var_dump($d);
+
+echo "\nUnset a protected property, and attempt to recreate it outside of scope (expected failure):\n";
+$d->unsetProtected();
+$d->p = 'this will fail';
+var_dump($d);
+?>
+--EXPECTF--
+Unset and recreate a protected property from property's declaring class scope:
+object(D)#%d (1) {
+ [%u|b%"p":protected]=>
+ %unicode|string%(7) "changed"
+}
+
+Unset and recreate a protected property from subclass:
+object(D)#%d (1) {
+ [%u|b%"p":protected]=>
+ %unicode|string%(12) "changed in D"
+}
+
+Unset a protected property, and attempt to recreate it outside of scope (expected failure):
+
+Fatal error: Cannot access protected property %s::$p in %s on line 32 \ No newline at end of file
diff --git a/tests/classes/protected_001.phpt b/tests/classes/protected_001.phpt
new file mode 100644
index 0000000..19872c6
--- /dev/null
+++ b/tests/classes/protected_001.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 A protected method can only be called inside the class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ protected static function fail() {
+ echo "Call fail()\n";
+ }
+
+ public static function good() {
+ pass::fail();
+ }
+}
+
+pass::good();
+pass::fail();// must fail because we are calling from outside of class pass
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call fail()
+
+Fatal error: Call to protected method pass::fail() from context '' in %s on line %d
diff --git a/tests/classes/protected_001b.phpt b/tests/classes/protected_001b.phpt
new file mode 100644
index 0000000..4d24a92
--- /dev/null
+++ b/tests/classes/protected_001b.phpt
@@ -0,0 +1,27 @@
+--TEST--
+ZE2 A protected method can only be called inside the class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ protected function fail() {
+ echo "Call fail()\n";
+ }
+
+ public function good() {
+ $this->fail();
+ }
+}
+
+$t = new pass();
+$t->good();
+$t->fail();// must fail because we are calling from outside of class pass
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call fail()
+
+Fatal error: Call to protected method pass::fail() from context '' in %s on line %d
diff --git a/tests/classes/protected_002.phpt b/tests/classes/protected_002.phpt
new file mode 100644
index 0000000..f26ef9c
--- /dev/null
+++ b/tests/classes/protected_002.phpt
@@ -0,0 +1,35 @@
+--TEST--
+ZE2 A protected method cannot be called in another class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ protected static function show() {
+ echo "Call pass::show()\n";
+ }
+
+ public static function do_show() {
+ pass::show();
+ }
+}
+
+pass::do_show();
+
+class fail {
+ public static function show() {
+ echo "Call fail::show()\n";
+ pass::show();
+ }
+}
+
+fail::show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Call pass::show()
+Call fail::show()
+
+Fatal error: Call to protected method pass::show() from context 'fail' in %s on line %d
diff --git a/tests/classes/serialize_001.phpt b/tests/classes/serialize_001.phpt
new file mode 100644
index 0000000..142fc50
--- /dev/null
+++ b/tests/classes/serialize_001.phpt
@@ -0,0 +1,79 @@
+--TEST--
+ZE2 Serializable
+--FILE--
+<?php
+
+class Test implements Serializable
+{
+ public $data;
+
+ function __construct($data)
+ {
+ echo __METHOD__ . "($data)\n";
+ $this->data = $data;
+ }
+
+ function serialize()
+ {
+ echo __METHOD__ . "({$this->data})\n";
+ return $this->data;
+ }
+
+ function unserialize($serialized)
+ {
+ echo __METHOD__ . "($serialized)\n";
+ $this->data = $serialized;
+ var_dump($this);
+ }
+}
+
+$tests = array('String', NULL, 42, false);
+
+foreach($tests as $data)
+{
+ try
+ {
+ echo "==========\n";
+ var_dump($data);
+ $ser = serialize(new Test($data));
+ var_dump(unserialize($ser));
+ }
+ catch(Exception $e)
+ {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+ }
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+==========
+%unicode|string%(6) "String"
+Test::__construct(String)
+Test::serialize(String)
+Test::unserialize(String)
+object(Test)#%d (1) {
+ [%u|b%"data"]=>
+ %unicode|string%(6) "String"
+}
+object(Test)#%d (1) {
+ [%u|b%"data"]=>
+ %unicode|string%(6) "String"
+}
+==========
+NULL
+Test::__construct()
+Test::serialize()
+NULL
+==========
+int(42)
+Test::__construct(42)
+Test::serialize(42)
+Exception: Test::serialize() must return a string or NULL
+==========
+bool(false)
+Test::__construct()
+Test::serialize()
+Exception: Test::serialize() must return a string or NULL
+===DONE===
diff --git a/tests/classes/singleton_001.phpt b/tests/classes/singleton_001.phpt
new file mode 100644
index 0000000..ee729b9
--- /dev/null
+++ b/tests/classes/singleton_001.phpt
@@ -0,0 +1,37 @@
+--TEST--
+ZE2 singleton
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Counter {
+ private $counter = 0;
+
+ function increment_and_print() {
+ echo ++$this->counter;
+ echo "\n";
+ }
+}
+
+
+class SingletonCounter {
+ private static $m_instance = NULL;
+
+ static function Instance() {
+ if (self::$m_instance == NULL) {
+ self::$m_instance = new Counter();
+ }
+ return self::$m_instance;
+ }
+}
+
+SingletonCounter::Instance()->increment_and_print();
+SingletonCounter::Instance()->increment_and_print();
+SingletonCounter::Instance()->increment_and_print();
+
+?>
+--EXPECT--
+1
+2
+3
diff --git a/tests/classes/static_mix_1.phpt b/tests/classes/static_mix_1.phpt
new file mode 100644
index 0000000..ecc9c01
--- /dev/null
+++ b/tests/classes/static_mix_1.phpt
@@ -0,0 +1,26 @@
+--TEST--
+ZE2 You cannot overload a static method with a non static method
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ static function show() {
+ echo "Call to function pass::show()\n";
+ }
+}
+
+class fail extends pass {
+ function show() {
+ echo "Call to function fail::show()\n";
+ }
+}
+
+pass::show();
+fail::show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Cannot make static method pass::show() non static in class fail in %s on line %d \ No newline at end of file
diff --git a/tests/classes/static_mix_2.phpt b/tests/classes/static_mix_2.phpt
new file mode 100644
index 0000000..bbdaedf
--- /dev/null
+++ b/tests/classes/static_mix_2.phpt
@@ -0,0 +1,27 @@
+--TEST--
+ZE2 You cannot overload a non static method with a static method
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class pass {
+ function show() {
+ echo "Call to function pass::show()\n";
+ }
+}
+
+class fail extends pass {
+ static function show() {
+ echo "Call to function fail::show()\n";
+ }
+}
+
+$t = new pass();
+$t->show();
+fail::show();
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Cannot make non static method pass::show() static in class fail in %s on line %d \ No newline at end of file
diff --git a/tests/classes/static_properties_001.phpt b/tests/classes/static_properties_001.phpt
new file mode 100644
index 0000000..1c34f68
--- /dev/null
+++ b/tests/classes/static_properties_001.phpt
@@ -0,0 +1,27 @@
+--TEST--
+ZE2 Initializing static properties to arrays
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class test {
+ static public $ar = array();
+}
+
+var_dump(test::$ar);
+
+test::$ar[] = 1;
+
+var_dump(test::$ar);
+
+echo "Done\n";
+?>
+--EXPECTF--
+array(0) {
+}
+array(1) {
+ [0]=>
+ int(1)
+}
+Done
diff --git a/tests/classes/static_properties_003.phpt b/tests/classes/static_properties_003.phpt
new file mode 100644
index 0000000..2441e41
--- /dev/null
+++ b/tests/classes/static_properties_003.phpt
@@ -0,0 +1,49 @@
+--TEST--
+Attempting to access static properties using instance property syntax
+--FILE--
+<?php
+class C {
+ public static $x = 'C::$x';
+ protected static $y = 'C::$y';
+}
+
+$c = new C;
+
+echo "\n--> Access visible static prop like instance prop:\n";
+var_dump(isset($c->x));
+unset($c->x);
+echo $c->x;
+$c->x = 1;
+$ref = 'ref';
+$c->x =& $ref;
+var_dump($c->x, C::$x);
+
+echo "\n--> Access non-visible static prop like instance prop:\n";
+var_dump(isset($c->y));
+//unset($c->y); // Fatal error, tested in static_properties_003_error1.phpt
+//echo $c->y; // Fatal error, tested in static_properties_003_error2.phpt
+//$c->y = 1; // Fatal error, tested in static_properties_003_error3.phpt
+//$c->y =& $ref; // Fatal error, tested in static_properties_003_error4.phpt
+?>
+==Done==
+--EXPECTF--
+--> Access visible static prop like instance prop:
+bool(false)
+
+Strict Standards: Accessing static property C::$x as non static in %s on line 11
+
+Strict Standards: Accessing static property C::$x as non static in %s on line 12
+
+Notice: Undefined property: C::$x in %s on line 12
+
+Strict Standards: Accessing static property C::$x as non static in %s on line 13
+
+Strict Standards: Accessing static property C::$x as non static in %s on line 15
+
+Strict Standards: Accessing static property C::$x as non static in %s on line 16
+%unicode|string%(3) "ref"
+%unicode|string%(5) "C::$x"
+
+--> Access non-visible static prop like instance prop:
+bool(false)
+==Done== \ No newline at end of file
diff --git a/tests/classes/static_properties_003_error1.phpt b/tests/classes/static_properties_003_error1.phpt
new file mode 100644
index 0000000..7a5e3d9
--- /dev/null
+++ b/tests/classes/static_properties_003_error1.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Attempting to access static properties using instance property syntax
+--FILE--
+<?php
+class C {
+ protected static $y = 'C::$y';
+}
+$c = new C;
+
+echo "\n--> Access non-visible static prop like instance prop:\n";
+unset($c->y);
+?>
+==Done==
+--EXPECTF--
+
+--> Access non-visible static prop like instance prop:
+
+Fatal error: Cannot access protected property C::$y in %s on line 8
diff --git a/tests/classes/static_properties_003_error2.phpt b/tests/classes/static_properties_003_error2.phpt
new file mode 100644
index 0000000..589cc69
--- /dev/null
+++ b/tests/classes/static_properties_003_error2.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Attempting to access static properties using instance property syntax
+--FILE--
+<?php
+class C {
+ protected static $y = 'C::$y';
+}
+$c = new C;
+
+echo "\n--> Access non-visible static prop like instance prop:\n";
+echo $c->y;
+?>
+==Done==
+--EXPECTF--
+
+--> Access non-visible static prop like instance prop:
+
+Fatal error: Cannot access protected property C::$y in %s on line 8
diff --git a/tests/classes/static_properties_003_error3.phpt b/tests/classes/static_properties_003_error3.phpt
new file mode 100644
index 0000000..3e01e0e
--- /dev/null
+++ b/tests/classes/static_properties_003_error3.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Attempting to access static properties using instance property syntax
+--FILE--
+<?php
+class C {
+ protected static $y = 'C::$y';
+}
+$c = new C;
+
+echo "\n--> Access non-visible static prop like instance prop:\n";
+$c->y = 1;
+?>
+==Done==
+--EXPECTF--
+
+--> Access non-visible static prop like instance prop:
+
+Fatal error: Cannot access protected property C::$y in %s on line 8
diff --git a/tests/classes/static_properties_003_error4.phpt b/tests/classes/static_properties_003_error4.phpt
new file mode 100644
index 0000000..fd69a9f
--- /dev/null
+++ b/tests/classes/static_properties_003_error4.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Attempting to access static properties using instance property syntax
+--FILE--
+<?php
+class C {
+ protected static $y = 'C::$y';
+}
+$c = new C;
+
+echo "\n--> Access non-visible static prop like instance prop:\n";
+$c->y =& $ref;
+?>
+==Done==
+--EXPECTF--
+
+--> Access non-visible static prop like instance prop:
+
+Fatal error: Cannot access protected property C::$y in %s on line 8
diff --git a/tests/classes/static_properties_004.phpt b/tests/classes/static_properties_004.phpt
new file mode 100644
index 0000000..ce1d19d
--- /dev/null
+++ b/tests/classes/static_properties_004.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Inherited static properties can be separated from their reference set.
+--FILE--
+<?php
+class C { public static $p = 'original'; }
+class D extends C { }
+class E extends D { }
+
+echo "\nInherited static properties refer to the same value accross classes:\n";
+var_dump(C::$p, D::$p, E::$p);
+
+echo "\nChanging one changes all the others:\n";
+D::$p = 'changed.all';
+var_dump(C::$p, D::$p, E::$p);
+
+echo "\nBut because this is implemented using PHP references, the reference set can easily be split:\n";
+$ref = 'changed.one';
+D::$p =& $ref;
+var_dump(C::$p, D::$p, E::$p);
+?>
+==Done==
+--EXPECTF--
+Inherited static properties refer to the same value accross classes:
+%unicode|string%(8) "original"
+%unicode|string%(8) "original"
+%unicode|string%(8) "original"
+
+Changing one changes all the others:
+%unicode|string%(11) "changed.all"
+%unicode|string%(11) "changed.all"
+%unicode|string%(11) "changed.all"
+
+But because this is implemented using PHP references, the reference set can easily be split:
+%unicode|string%(11) "changed.all"
+%unicode|string%(11) "changed.one"
+%unicode|string%(11) "changed.all"
+==Done== \ No newline at end of file
diff --git a/tests/classes/static_properties_undeclared_assign.phpt b/tests/classes/static_properties_undeclared_assign.phpt
new file mode 100644
index 0000000..99340e9
--- /dev/null
+++ b/tests/classes/static_properties_undeclared_assign.phpt
@@ -0,0 +1,9 @@
+--TEST--
+Assigning to a non-existent static property
+--FILE--
+<?php
+Class C {}
+C::$p = 1;
+?>
+--EXPECTF--
+Fatal error: Access to undeclared static property: C::$p in %s on line 3 \ No newline at end of file
diff --git a/tests/classes/static_properties_undeclared_assignInc.phpt b/tests/classes/static_properties_undeclared_assignInc.phpt
new file mode 100644
index 0000000..258f2f8
--- /dev/null
+++ b/tests/classes/static_properties_undeclared_assignInc.phpt
@@ -0,0 +1,9 @@
+--TEST--
+Assigning & incrementing a non-existent static property
+--FILE--
+<?php
+Class C {}
+C::$p += 1;
+?>
+--EXPECTF--
+Fatal error: Access to undeclared static property: C::$p in %s on line 3 \ No newline at end of file
diff --git a/tests/classes/static_properties_undeclared_assignRef.phpt b/tests/classes/static_properties_undeclared_assignRef.phpt
new file mode 100644
index 0000000..75cf270
--- /dev/null
+++ b/tests/classes/static_properties_undeclared_assignRef.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Assigning a non-existent static property by reference
+--FILE--
+<?php
+Class C {}
+$a = 'foo';
+C::$p =& $a;
+?>
+--EXPECTF--
+Fatal error: Access to undeclared static property: C::$p in %s on line 4 \ No newline at end of file
diff --git a/tests/classes/static_properties_undeclared_inc.phpt b/tests/classes/static_properties_undeclared_inc.phpt
new file mode 100644
index 0000000..ff8b8c3
--- /dev/null
+++ b/tests/classes/static_properties_undeclared_inc.phpt
@@ -0,0 +1,9 @@
+--TEST--
+Incrementing a non-existent static property
+--FILE--
+<?php
+Class C {}
+C::$p++;
+?>
+--EXPECTF--
+Fatal error: Access to undeclared static property: C::$p in %s on line 3 \ No newline at end of file
diff --git a/tests/classes/static_properties_undeclared_isset.phpt b/tests/classes/static_properties_undeclared_isset.phpt
new file mode 100644
index 0000000..58aac40
--- /dev/null
+++ b/tests/classes/static_properties_undeclared_isset.phpt
@@ -0,0 +1,9 @@
+--TEST--
+Issetting a non-existent static property
+--FILE--
+<?php
+Class C {}
+var_dump(isset(C::$p));
+?>
+--EXPECTF--
+bool(false) \ No newline at end of file
diff --git a/tests/classes/static_properties_undeclared_read.phpt b/tests/classes/static_properties_undeclared_read.phpt
new file mode 100644
index 0000000..715b41e
--- /dev/null
+++ b/tests/classes/static_properties_undeclared_read.phpt
@@ -0,0 +1,9 @@
+--TEST--
+Reading a non-existent static property
+--FILE--
+<?php
+Class C {}
+echo C::$p;
+?>
+--EXPECTF--
+Fatal error: Access to undeclared static property: C::$p in %s on line 3 \ No newline at end of file
diff --git a/tests/classes/static_this.phpt b/tests/classes/static_this.phpt
new file mode 100644
index 0000000..91b0287
--- /dev/null
+++ b/tests/classes/static_this.phpt
@@ -0,0 +1,39 @@
+--TEST--
+ZE2 $this can be an argument to a static function
+--FILE--
+<?php
+
+class TestClass
+{
+ function __construct()
+ {
+ self::Test1();
+ $this->Test1();
+ }
+
+ static function Test1()
+ {
+ var_dump($this);
+ }
+
+ static function Test2($this)
+ {
+ var_dump($this);
+ }
+}
+
+$obj = new TestClass;
+TestClass::Test2(new stdClass);
+
+?>
+===DONE===
+--EXPECTF--
+
+Notice: Undefined variable: this in %sstatic_this.php on line %d
+NULL
+
+Notice: Undefined variable: this in %sstatic_this.php on line %d
+NULL
+object(stdClass)#%d (0) {
+}
+===DONE===
diff --git a/tests/classes/this.phpt b/tests/classes/this.phpt
new file mode 100644
index 0000000..1d9c623
--- /dev/null
+++ b/tests/classes/this.phpt
@@ -0,0 +1,54 @@
+--TEST--
+ZE2 $this cannot be exchanged
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+/* please don't shorten this test. It shows what would happen if
+ * the fatal error would have been a warning.
+ */
+class Foo
+{
+ function replace($other)
+ {
+ echo __METHOD__ . "\n";
+ $this = $other;
+ print $this->prop;
+ print $other->prop;
+ }
+
+ function indirect($other)
+ {
+ echo __METHOD__ . "\n";
+ $this = $other;
+ $result = $this = $other;
+ print $result->prop;
+ print $this->prop;
+ }
+
+ function retrieve(&$other)
+ {
+ echo __METHOD__ . "\n";
+ $other = $this;
+ }
+}
+
+$object = new Foo;
+$object->prop = "Hello\n";
+
+$other = new Foo;
+$other->prop = "World\n";
+
+$object->replace($other);
+$object->indirect($other);
+
+print $object->prop; // still shows 'Hello'
+
+$object->retrieve($other);
+print $other->prop; // shows 'Hello'
+
+?>
+===DONE===
+--EXPECTF--
+Fatal error: Cannot re-assign $this in %sthis.php on line %d
diff --git a/tests/classes/tostring_001.phpt b/tests/classes/tostring_001.phpt
new file mode 100644
index 0000000..53144ca
--- /dev/null
+++ b/tests/classes/tostring_001.phpt
@@ -0,0 +1,130 @@
+--TEST--
+ZE2 __toString()
+--FILE--
+<?php
+
+function my_error_handler($errno, $errstr, $errfile, $errline) {
+ var_dump($errstr);
+}
+
+set_error_handler('my_error_handler');
+
+class test1
+{
+}
+
+class test2
+{
+ function __toString()
+ {
+ echo __METHOD__ . "()\n";
+ return "Converted\n";
+ }
+}
+
+class test3
+{
+ function __toString()
+ {
+ echo __METHOD__ . "()\n";
+ return 42;
+ }
+}
+echo "====test1====\n";
+$o = new test1;
+print_r($o);
+var_dump((string)$o);
+var_dump($o);
+
+echo "====test2====\n";
+$o = new test2;
+print_r($o);
+print $o;
+var_dump($o);
+echo "====test3====\n";
+echo $o;
+
+echo "====test4====\n";
+echo "string:".$o;
+
+echo "====test5====\n";
+echo 1 . $o;
+echo 1 , $o;
+
+echo "====test6====\n";
+echo $o . $o;
+echo $o , $o;
+
+echo "====test7====\n";
+$ar = array();
+$ar[$o->__toString()] = "ERROR";
+echo $ar[$o];
+
+echo "====test8====\n";
+var_dump(trim($o));
+var_dump(trim((string)$o));
+
+echo "====test9====\n";
+echo sprintf("%s", $o);
+
+echo "====test10====\n";
+$o = new test3;
+var_dump($o);
+echo $o;
+
+?>
+====DONE====
+--EXPECTF--
+====test1====
+test1 Object
+(
+)
+string(54) "Object of class test1 could not be converted to string"
+string(0) ""
+object(test1)#%d (0) {
+}
+====test2====
+test2 Object
+(
+)
+test2::__toString()
+Converted
+object(test2)#%d (0) {
+}
+====test3====
+test2::__toString()
+Converted
+====test4====
+test2::__toString()
+string:Converted
+====test5====
+test2::__toString()
+1Converted
+1test2::__toString()
+Converted
+====test6====
+test2::__toString()
+test2::__toString()
+Converted
+Converted
+test2::__toString()
+Converted
+test2::__toString()
+Converted
+====test7====
+test2::__toString()
+string(19) "Illegal offset type"
+====test8====
+test2::__toString()
+string(9) "Converted"
+test2::__toString()
+string(9) "Converted"
+====test9====
+test2::__toString()
+Converted
+====test10====
+object(test3)#%d (0) {
+}
+test3::__toString()
+string(53) "Method test3::__toString() must return a string value"
+====DONE====
diff --git a/tests/classes/tostring_002.phpt b/tests/classes/tostring_002.phpt
new file mode 100644
index 0000000..8a4a7af
--- /dev/null
+++ b/tests/classes/tostring_002.phpt
@@ -0,0 +1,31 @@
+--TEST--
+ZE2 __toString() in __destruct
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Test
+{
+ function __toString()
+ {
+ return "Hello\n";
+ }
+
+ function __destruct()
+ {
+ echo $this;
+ }
+}
+
+$o = new Test;
+$o = NULL;
+
+$o = new Test;
+
+?>
+====DONE====
+--EXPECTF--
+Hello
+====DONE====
+Hello
diff --git a/tests/classes/tostring_003.phpt b/tests/classes/tostring_003.phpt
new file mode 100644
index 0000000..8815bd9
--- /dev/null
+++ b/tests/classes/tostring_003.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 __toString() in __destruct/exception
+--FILE--
+<?php
+
+class Test
+{
+ function __toString()
+ {
+ throw new Exception("Damn!");
+ return "Hello\n";
+ }
+
+ function __destruct()
+ {
+ echo $this;
+ }
+}
+
+try
+{
+ $o = new Test;
+ $o = NULL;
+}
+catch(Exception $e)
+{
+ var_dump($e->getMessage());
+}
+
+?>
+====DONE====
+--EXPECTF--
+Fatal error: Method Test::__toString() must not throw an exception in %stostring_003.php on line %d
diff --git a/tests/classes/tostring_004.phpt b/tests/classes/tostring_004.phpt
new file mode 100644
index 0000000..de0283e
--- /dev/null
+++ b/tests/classes/tostring_004.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Object to string conversion: error cases and behaviour variations.
+--FILE--
+<?php
+function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) {
+ echo "Error: $err_no - $err_msg\n";
+}
+set_error_handler('test_error_handler');
+error_reporting(8191);
+
+
+echo "Object with no __toString():\n";
+$obj = new stdClass;
+echo "Try 1:\n";
+printf($obj);
+printf("\n");
+
+echo "\nTry 2:\n";
+printf($obj . "\n");
+
+
+echo "\n\nObject with bad __toString():\n";
+class badToString {
+ function __toString() {
+ return 0;
+ }
+}
+$obj = new badToString;
+echo "Try 1:\n";
+printf($obj);
+printf("\n");
+
+echo "\nTry 2:\n";
+printf($obj . "\n");
+
+?>
+--EXPECTF--
+Object with no __toString():
+Try 1:
+Error: 4096 - Object of class stdClass could not be converted to string
+Error: 8 - Object of class stdClass to string conversion
+Object
+
+Try 2:
+Error: 4096 - Object of class stdClass could not be converted to string
+
+
+
+Object with bad __toString():
+Try 1:
+Error: 4096 - Method badToString::__toString() must return a string value
+
+
+Try 2:
+Error: 4096 - Method badToString::__toString() must return a string value
+
diff --git a/tests/classes/type_hinting_001.phpt b/tests/classes/type_hinting_001.phpt
new file mode 100644
index 0000000..f55dd53
--- /dev/null
+++ b/tests/classes/type_hinting_001.phpt
@@ -0,0 +1,38 @@
+--TEST--
+ZE2 class type hinting
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?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) {
+ // ...
+ }
+}
+
+class Blort {
+}
+
+$a = new FooBar;
+$b = new Blort;
+
+$a->a($b);
+$a->b($b);
+
+?>
+--EXPECTF--
+
+Catchable fatal error: Argument 1 passed to FooBar::a() must implement interface Foo, instance of Blort given, called in %s on line 27 and defined in %s on line 12
diff --git a/tests/classes/type_hinting_002.phpt b/tests/classes/type_hinting_002.phpt
new file mode 100644
index 0000000..7c685bf
--- /dev/null
+++ b/tests/classes/type_hinting_002.phpt
@@ -0,0 +1,16 @@
+--TEST--
+ZE2 class type hinting non existing class
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class Foo {
+ function a(NonExisting $foo) {}
+}
+
+$o = new Foo;
+$o->a($o);
+?>
+--EXPECTF--
+Catchable fatal error: Argument 1 passed to Foo::a() must be an instance of NonExisting, instance of Foo given, called in %s on line %d and defined in %s on line %d
diff --git a/tests/classes/type_hinting_003.phpt b/tests/classes/type_hinting_003.phpt
new file mode 100644
index 0000000..a966210
--- /dev/null
+++ b/tests/classes/type_hinting_003.phpt
@@ -0,0 +1,60 @@
+--TEST--
+ZE2 class type hinting with arrays
+--FILE--
+<?php
+
+class Test
+{
+ static function f1(array $ar)
+ {
+ echo __METHOD__ . "()\n";
+ var_dump($ar);
+ }
+
+ static function f2(array $ar = NULL)
+ {
+ echo __METHOD__ . "()\n";
+ var_dump($ar);
+ }
+
+ static function f3(array $ar = array())
+ {
+ echo __METHOD__ . "()\n";
+ var_dump($ar);
+ }
+
+ static function f4(array $ar = array(25))
+ {
+ echo __METHOD__ . "()\n";
+ var_dump($ar);
+ }
+}
+
+Test::f1(array(42));
+Test::f2(NULL);
+Test::f2();
+Test::f3();
+Test::f4();
+Test::f1(1);
+
+?>
+--EXPECTF--
+Test::f1()
+array(1) {
+ [0]=>
+ int(42)
+}
+Test::f2()
+NULL
+Test::f2()
+NULL
+Test::f3()
+array(0) {
+}
+Test::f4()
+array(1) {
+ [0]=>
+ int(25)
+}
+
+Catchable fatal error: Argument 1 passed to Test::f1() must be of the type array, integer given, called in %s on line %d and defined in %s on line %d
diff --git a/tests/classes/type_hinting_004.phpt b/tests/classes/type_hinting_004.phpt
new file mode 100644
index 0000000..9068909
--- /dev/null
+++ b/tests/classes/type_hinting_004.phpt
@@ -0,0 +1,109 @@
+--TEST--
+Ensure type hints are enforced for functions invoked as callbacks.
+--FILE--
+<?php
+ set_error_handler('myErrorHandler', E_RECOVERABLE_ERROR);
+ function myErrorHandler($errno, $errstr, $errfile, $errline) {
+ echo "$errno: $errstr - $errfile($errline)\n";
+ return true;
+ }
+
+ echo "---> Type hints with callback function:\n";
+ class A { }
+ function f1(A $a) {
+ echo "in f1;\n";
+ }
+ function f2(A $a = null) {
+ echo "in f2;\n";
+ }
+ call_user_func('f1', 1);
+ call_user_func('f1', new A);
+ call_user_func('f2', 1);
+ call_user_func('f2');
+ call_user_func('f2', new A);
+ call_user_func('f2', null);
+
+
+ echo "\n\n---> Type hints with callback static method:\n";
+ class C {
+ static function f1(A $a) {
+ if (isset($this)) {
+ echo "in C::f1 (instance);\n";
+ } else {
+ echo "in C::f1 (static);\n";
+ }
+ }
+ static function f2(A $a = null) {
+ if (isset($this)) {
+ echo "in C::f2 (instance);\n";
+ } else {
+ echo "in C::f2 (static);\n";
+ }
+ }
+ }
+ call_user_func(array('C', 'f1'), 1);
+ call_user_func(array('C', 'f1'), new A);
+ call_user_func(array('C', 'f2'), 1);
+ call_user_func(array('C', 'f2'));
+ call_user_func(array('C', 'f2'), new A);
+ call_user_func(array('C', 'f2'), null);
+
+
+ echo "\n\n---> Type hints with callback instance method:\n";
+ class D {
+ function f1(A $a) {
+ if (isset($this)) {
+ echo "in C::f1 (instance);\n";
+ } else {
+ echo "in C::f1 (static);\n";
+ }
+ }
+ function f2(A $a = null) {
+ if (isset($this)) {
+ echo "in C::f2 (instance);\n";
+ } else {
+ echo "in C::f2 (static);\n";
+ }
+ }
+ }
+ $d = new D;
+ call_user_func(array($d, 'f1'), 1);
+ call_user_func(array($d, 'f1'), new A);
+ call_user_func(array($d, 'f2'), 1);
+ call_user_func(array($d, 'f2'));
+ call_user_func(array($d, 'f2'), new A);
+ call_user_func(array($d, 'f2'), null);
+
+?>
+--EXPECTF--
+---> Type hints with callback function:
+4096: Argument 1 passed to f1() must be an instance of A, integer given%s(10)
+in f1;
+in f1;
+4096: Argument 1 passed to f2() must be an instance of A, integer given%s(13)
+in f2;
+in f2;
+in f2;
+in f2;
+
+
+---> Type hints with callback static method:
+4096: Argument 1 passed to C::f1() must be an instance of A, integer given%s(26)
+in C::f1 (static);
+in C::f1 (static);
+4096: Argument 1 passed to C::f2() must be an instance of A, integer given%s(33)
+in C::f2 (static);
+in C::f2 (static);
+in C::f2 (static);
+in C::f2 (static);
+
+
+---> Type hints with callback instance method:
+4096: Argument 1 passed to D::f1() must be an instance of A, integer given%s(51)
+in C::f1 (instance);
+in C::f1 (instance);
+4096: Argument 1 passed to D::f2() must be an instance of A, integer given%s(58)
+in C::f2 (instance);
+in C::f2 (instance);
+in C::f2 (instance);
+in C::f2 (instance);
diff --git a/tests/classes/type_hinting_005a.phpt b/tests/classes/type_hinting_005a.phpt
new file mode 100644
index 0000000..5e4c43b
--- /dev/null
+++ b/tests/classes/type_hinting_005a.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Check type hint compatibility in overrides with array hints.
+--FILE--
+<?php
+Class C { function f(array $a) {} }
+
+echo "Compatible hint.\n";
+Class D1 extends C { function f(array $a) {} }
+
+echo "Class hint, should be array.\n";
+Class D2 extends C { function f(SomeClass $a) {} }
+?>
+==DONE==
+--EXPECTF--
+Strict Standards: Declaration of D2::f() should be compatible with C::f(array $a) in %s on line 8
+Compatible hint.
+Class hint, should be array.
+==DONE==
diff --git a/tests/classes/type_hinting_005b.phpt b/tests/classes/type_hinting_005b.phpt
new file mode 100644
index 0000000..f13ab95
--- /dev/null
+++ b/tests/classes/type_hinting_005b.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Check type hint compatibility in overrides with array hints.
+--FILE--
+<?php
+Class C { function f(array $a) {} }
+
+echo "No hint, should be array.\n";
+Class D extends C { function f($a) {} }
+?>
+==DONE==
+--EXPECTF--
+Strict Standards: Declaration of D::f() should be compatible with C::f(array $a) in %s on line 5
+No hint, should be array.
+==DONE==
diff --git a/tests/classes/type_hinting_005c.phpt b/tests/classes/type_hinting_005c.phpt
new file mode 100644
index 0000000..30a114e
--- /dev/null
+++ b/tests/classes/type_hinting_005c.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Check type hint compatibility in overrides with array hints.
+--FILE--
+<?php
+Class C { function f(SomeClass $a) {} }
+
+echo "Array hint, should be class.\n";
+Class D extends C { function f(array $a) {} }
+?>
+==DONE==
+--EXPECTF--
+Strict Standards: Declaration of D::f() should be compatible with C::f(SomeClass $a) in %s on line 5
+Array hint, should be class.
+==DONE==
diff --git a/tests/classes/type_hinting_005d.phpt b/tests/classes/type_hinting_005d.phpt
new file mode 100644
index 0000000..830054d
--- /dev/null
+++ b/tests/classes/type_hinting_005d.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Check type hint compatibility in overrides with array hints.
+--FILE--
+<?php
+Class C { function f($a) {} }
+
+echo "Array hint, should be nothing.\n";
+Class D extends C { function f(array $a) {} }
+?>
+==DONE==
+--EXPECTF--
+Strict Standards: Declaration of D::f() should be compatible with C::f($a) in %s on line 5
+Array hint, should be nothing.
+==DONE==
diff --git a/tests/classes/unset_properties.phpt b/tests/classes/unset_properties.phpt
new file mode 100644
index 0000000..264e720
--- /dev/null
+++ b/tests/classes/unset_properties.phpt
@@ -0,0 +1,154 @@
+--TEST--
+Un-setting instance properties causes magic methods to be called when trying to access them from outside the magic
+methods themselves.
+--FILE--
+<?php
+
+class Test
+{
+ public $publicProperty = 'publicProperty set';
+
+ protected $protectedProperty = 'protectedProperty set';
+
+ private $privateProperty = 'privateProperty set';
+
+ public function __get($name)
+ {
+ return '__get "' . $name . '"';
+ }
+
+ public function __set($name, $value)
+ {
+ $this->$name = $value;
+ echo '__set "' . $name . '" to "' . $value . '"';
+ }
+
+ public function __isset($name)
+ {
+ echo '__isset "' . $name . '"';
+ return isset($this->$name);
+ }
+
+ public function getPublicProperty()
+ {
+ return $this->publicProperty;
+ }
+
+ public function setPublicProperty($publicProperty)
+ {
+ $this->publicProperty = $publicProperty;
+ }
+
+ public function unsetProtectedProperty()
+ {
+ unset($this->protectedProperty);
+ }
+
+ public function getProtectedProperty()
+ {
+ return $this->protectedProperty;
+ }
+
+ public function setProtectedProperty($protectedProperty)
+ {
+ $this->protectedProperty = $protectedProperty;
+ }
+
+ public function unsetPrivateProperty()
+ {
+ unset($this->privateProperty);
+ }
+
+ public function getPrivateProperty()
+ {
+ return $this->privateProperty;
+ }
+
+ public function setPrivateProperty($privateProperty)
+ {
+ $this->privateProperty = $privateProperty;
+ }
+}
+
+// verifying public property
+$o = new Test;
+echo $o->publicProperty;
+echo "\n";
+var_export(isset($o->publicProperty));
+echo "\n";
+unset($o->publicProperty);
+isset($o->publicProperty);
+echo "\n";
+echo $o->publicProperty;
+echo "\n";
+echo $o->getPublicProperty();
+echo "\n";
+echo $o->setPublicProperty('new publicProperty value via setter');
+echo "\n";
+echo $o->publicProperty;
+echo "\n";
+unset($o->publicProperty);
+$o->publicProperty = 'new publicProperty value via public access';
+echo "\n";
+var_export(isset($o->publicProperty));
+echo "\n";
+echo $o->publicProperty;
+echo "\n\n";
+
+// verifying protected property
+echo $o->getProtectedProperty();
+echo "\n";
+$o->unsetProtectedProperty();
+var_export(isset($o->protectedProperty));
+echo "\n";
+echo $o->getProtectedProperty();
+echo "\n";
+echo $o->setProtectedProperty('new protectedProperty value via setter');
+echo "\n";
+var_export(isset($o->protectedProperty));
+echo "\n";
+echo $o->getProtectedProperty();
+echo "\n\n";
+
+// verifying private property
+echo $o->getPrivateProperty();
+echo "\n";
+$o->unsetPrivateProperty();
+var_export(isset($o->privateProperty));
+echo "\n";
+echo $o->getPrivateProperty();
+echo "\n";
+echo $o->setPrivateProperty('new privateProperty value via setter');
+echo "\n";
+var_export(isset($o->privateProperty));
+echo "\n";
+echo $o->getPrivateProperty();
+echo "\n\n";
+
+?>
+
+--EXPECTF--
+publicProperty set
+true
+__isset "publicProperty"
+__get "publicProperty"
+__get "publicProperty"
+__set "publicProperty" to "new publicProperty value via setter"
+new publicProperty value via setter
+__set "publicProperty" to "new publicProperty value via public access"
+true
+new publicProperty value via public access
+
+protectedProperty set
+__isset "protectedProperty"false
+__get "protectedProperty"
+__set "protectedProperty" to "new protectedProperty value via setter"
+__isset "protectedProperty"true
+new protectedProperty value via setter
+
+privateProperty set
+__isset "privateProperty"false
+__get "privateProperty"
+__set "privateProperty" to "new privateProperty value via setter"
+__isset "privateProperty"true
+new privateProperty value via setter
diff --git a/tests/classes/visibility_000a.phpt b/tests/classes/visibility_000a.phpt
new file mode 100644
index 0000000..2524494
--- /dev/null
+++ b/tests/classes/visibility_000a.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ protected function f0() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Access level to fail::f0() must be public (as in class same) in %s on line %d
diff --git a/tests/classes/visibility_000b.phpt b/tests/classes/visibility_000b.phpt
new file mode 100644
index 0000000..9305467
--- /dev/null
+++ b/tests/classes/visibility_000b.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ private function f0() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Access level to fail::f0() must be public (as in class same) in %s on line %d
diff --git a/tests/classes/visibility_000c.phpt b/tests/classes/visibility_000c.phpt
new file mode 100644
index 0000000..064106e
--- /dev/null
+++ b/tests/classes/visibility_000c.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ function f0() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_001a.phpt b/tests/classes/visibility_001a.phpt
new file mode 100644
index 0000000..ebd1cc3
--- /dev/null
+++ b/tests/classes/visibility_001a.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ protected function f1() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Access level to fail::f1() must be public (as in class same) in %s on line %d
diff --git a/tests/classes/visibility_001b.phpt b/tests/classes/visibility_001b.phpt
new file mode 100644
index 0000000..e61078e
--- /dev/null
+++ b/tests/classes/visibility_001b.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ private function f1() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Access level to fail::f1() must be public (as in class same) in %s on line %d
diff --git a/tests/classes/visibility_001c.phpt b/tests/classes/visibility_001c.phpt
new file mode 100644
index 0000000..bb1075a
--- /dev/null
+++ b/tests/classes/visibility_001c.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ function f1() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_002a.phpt b/tests/classes/visibility_002a.phpt
new file mode 100644
index 0000000..6c88d20
--- /dev/null
+++ b/tests/classes/visibility_002a.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ protected function f2() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Access level to fail::f2() must be public (as in class same) in %s on line %d
diff --git a/tests/classes/visibility_002b.phpt b/tests/classes/visibility_002b.phpt
new file mode 100644
index 0000000..71f47c3
--- /dev/null
+++ b/tests/classes/visibility_002b.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ private function f2() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Access level to fail::f2() must be public (as in class same) in %s on line %d
diff --git a/tests/classes/visibility_002c.phpt b/tests/classes/visibility_002c.phpt
new file mode 100644
index 0000000..5edae1d
--- /dev/null
+++ b/tests/classes/visibility_002c.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ function f2() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_003a.phpt b/tests/classes/visibility_003a.phpt
new file mode 100644
index 0000000..1693386
--- /dev/null
+++ b/tests/classes/visibility_003a.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ public function f3() {}
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_003b.phpt b/tests/classes/visibility_003b.phpt
new file mode 100644
index 0000000..fcfdbe3
--- /dev/null
+++ b/tests/classes/visibility_003b.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ private function f3() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Fatal error: Access level to fail::f3() must be protected (as in class same) or weaker in %s on line %d
diff --git a/tests/classes/visibility_003c.phpt b/tests/classes/visibility_003c.phpt
new file mode 100644
index 0000000..d94a9c1
--- /dev/null
+++ b/tests/classes/visibility_003c.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ function f3() {}
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_004a.phpt b/tests/classes/visibility_004a.phpt
new file mode 100644
index 0000000..6f16a09
--- /dev/null
+++ b/tests/classes/visibility_004a.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ public function f4() {}
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_004b.phpt b/tests/classes/visibility_004b.phpt
new file mode 100644
index 0000000..74a8318
--- /dev/null
+++ b/tests/classes/visibility_004b.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ protected function f4() {}
+}
+
+echo "Done\n"; // shouldn't be displayed
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_004c.phpt b/tests/classes/visibility_004c.phpt
new file mode 100644
index 0000000..92a7703
--- /dev/null
+++ b/tests/classes/visibility_004c.phpt
@@ -0,0 +1,33 @@
+--TEST--
+ZE2 A redeclared method must have the same or higher visibility
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+class father {
+ function f0() {}
+ function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class same extends father {
+
+ // overload fn with same visibility
+ function f0() {}
+ public function f1() {}
+ public function f2() {}
+ protected function f3() {}
+ private function f4() {}
+}
+
+class fail extends same {
+ function f4() {}
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Done
diff --git a/tests/classes/visibility_005.phpt b/tests/classes/visibility_005.phpt
new file mode 100644
index 0000000..859a5f7
--- /dev/null
+++ b/tests/classes/visibility_005.phpt
@@ -0,0 +1,59 @@
+--TEST--
+ZE2 foreach and property visibility
+--FILE--
+<?php
+
+class base
+{
+ public $a=1;
+ protected $b=2;
+ private $c=3;
+
+ function f()
+ {
+ foreach($this as $k=>$v) {
+ echo "$k=>$v\n";
+ }
+ }
+}
+
+class derived extends base
+{
+}
+
+$o = new base;
+$o->d = 4;
+echo "===base::function===\n";
+$o->f();
+echo "===base,foreach===\n";
+foreach($o as $k=>$v) {
+ echo "$k=>$v\n";
+}
+
+$o = new derived;
+$o->d = 4;
+echo "===derived::function===\n";
+$o->f();
+echo "===derived,foreach===\n";
+foreach($o as $k=>$v) {
+ echo "$k=>$v\n";
+}
+
+?>
+--EXPECT--
+===base::function===
+a=>1
+b=>2
+c=>3
+d=>4
+===base,foreach===
+a=>1
+d=>4
+===derived::function===
+a=>1
+b=>2
+c=>3
+d=>4
+===derived,foreach===
+a=>1
+d=>4