Skip to content

Commit

Permalink
Rebase Joe's anon classes implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
krakjoe authored and nikic committed Apr 26, 2015
1 parent 1a4d3e4 commit 49608e0
Show file tree
Hide file tree
Showing 19 changed files with 438 additions and 44 deletions.
10 changes: 10 additions & 0 deletions Zend/tests/anon/001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
declare bare anonymous class
--FILE--
<?php
var_dump(new class{});
--EXPECTF--
object(class@%s)#%d (0) {
}


21 changes: 21 additions & 0 deletions Zend/tests/anon/002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
declare anonymous class extending another
--FILE--
<?php
class A{}

interface B{
public function method();
}

$a = new class extends A implements B {
public function method(){
return true;
}
};

var_dump($a instanceof A, $a instanceof B);
--EXPECTF--
bool(true)
bool(true)

54 changes: 54 additions & 0 deletions Zend/tests/anon/003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--TEST--
reusing anonymous classes
--FILE--
<?php
while (@$i++<10) {
var_dump(new class($i) {

public function __construct($i) {
$this->i = $i;
}
});
}
--EXPECTF--
object(class@%s)#1 (1) {
["i"]=>
int(1)
}
object(class@%s)#1 (1) {
["i"]=>
int(2)
}
object(class@%s)#1 (1) {
["i"]=>
int(3)
}
object(class@%s)#1 (1) {
["i"]=>
int(4)
}
object(class@%s)#1 (1) {
["i"]=>
int(5)
}
object(class@%s)#1 (1) {
["i"]=>
int(6)
}
object(class@%s)#1 (1) {
["i"]=>
int(7)
}
object(class@%s)#1 (1) {
["i"]=>
int(8)
}
object(class@%s)#1 (1) {
["i"]=>
int(9)
}
object(class@%s)#1 (1) {
["i"]=>
int(10)
}

30 changes: 30 additions & 0 deletions Zend/tests/anon/004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
testing anonymous inheritance
--FILE--
<?php
class Outer {
protected $data;

public function __construct($data) {
$this->data = $data;
}

public function getArrayAccess() {
/* create a proxy object implementing array access */
return new class($this->data) extends Outer implements ArrayAccess {
public function offsetGet($offset) { return $this->data[$offset]; }
public function offsetSet($offset, $data) { return ($this->data[$offset] = $data); }
public function offsetUnset($offset) { unset($this->data[$offset]); }
public function offsetExists($offset) { return isset($this->data[$offset]); }
};
}
}

$outer = new Outer(array(
rand(1, 100)
));

/* not null because inheritance */
var_dump($outer->getArrayAccess()[0]);
--EXPECTF--
int(%d)
36 changes: 36 additions & 0 deletions Zend/tests/anon/005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
testing reusing anons that implement an interface
--FILE--
<?php
class Outer {
protected $data;

public function __construct(&$data) {
/* array access will be implemented by the time we get to here */
$this->data = &$data;
}

public function getArrayAccess() {
/* create a child object implementing array access */
/* this grants you access to protected methods and members */
return new class($this->data) implements ArrayAccess {
public function offsetGet($offset) { return $this->data[$offset]; }
public function offsetSet($offset, $data) { return ($this->data[$offset] = $data); }
public function offsetUnset($offset) { unset($this->data[$offset]); }
public function offsetExists($offset) { return isset($this->data[$offset]); }
};
}
}

$data = array(
rand(1, 100),
rand(2, 200)
);

$outer = new Outer($data);
$proxy = $outer->getArrayAccess();

/* null because no inheritance, so no access to protected member */
var_dump(@$outer->getArrayAccess()[0]);
--EXPECT--
NULL
15 changes: 15 additions & 0 deletions Zend/tests/anon/006.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
testing anon classes inside namespaces
--FILE--
<?php
namespace lone {
$hello = new class{} ;
}

namespace {
var_dump ($hello);
}
--EXPECTF--
object(lone\class@%s)#1 (0) {
}

23 changes: 23 additions & 0 deletions Zend/tests/anon/007.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
testing anon classes in functions outside of classes in namespaces
--FILE--
<?php
namespace lone {
function my_factory() {
return new class{};
}

class Outer {

public function __construct() {
var_dump(
my_factory());
}
}

new Outer();
}
--EXPECTF--
object(lone\class@%s)#2 (0) {
}

23 changes: 23 additions & 0 deletions Zend/tests/anon/008.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
testing static access for methods and properties in anon classes
--FILE--
<?php
$anonClass = new class("cats", "dogs") {
public static $foo;
private static $bar;

public function __construct($foo, $bar) {
static::$foo = $foo;
static::$bar = $bar;
}

public static function getBar() {
return static::$bar;
}
};

var_dump($anonClass::$foo);
var_dump($anonClass::getBar());
--EXPECT--
string(4) "cats"
string(4) "dogs"
18 changes: 18 additions & 0 deletions Zend/tests/anon/009.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
testing traits in anon classes
--FILE--
<?php

trait Foo {
public function someMethod() {
return "bar";
}
}

$anonClass = new class {
use Foo;
};

var_dump($anonClass->someMethod());
--EXPECT--
string(3) "bar"
4 changes: 3 additions & 1 deletion Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,9 @@ static void zend_ast_destroy_ex(zend_ast *ast, zend_bool free) {
case ZEND_AST_CLASS:
{
zend_ast_decl *decl = (zend_ast_decl *) ast;
zend_string_release(decl->name);
if (decl->name) {
zend_string_release(decl->name);
}
if (decl->doc_comment) {
zend_string_release(decl->doc_comment);
}
Expand Down
23 changes: 16 additions & 7 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_create_function, 0, 0, 2)
ZEND_ARG_INFO(0, code)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_get_defined_functions, 0, 0, 0)
ZEND_ARG_INFO(0, disabled)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_get_resource_type, 0, 0, 1)
ZEND_ARG_INFO(0, res)
ZEND_END_ARG_INFO()
Expand Down Expand Up @@ -302,7 +306,7 @@ static const zend_function_entry builtin_functions[] = { /* {{{ */
ZEND_FE(get_declared_classes, arginfo_zend__void)
ZEND_FE(get_declared_traits, arginfo_zend__void)
ZEND_FE(get_declared_interfaces, arginfo_zend__void)
ZEND_FE(get_defined_functions, arginfo_zend__void)
ZEND_FE(get_defined_functions, arginfo_get_defined_functions)
ZEND_FE(get_defined_vars, arginfo_zend__void)
ZEND_FE(create_function, arginfo_create_function)
ZEND_FE(get_resource_type, arginfo_get_resource_type)
Expand Down Expand Up @@ -1860,15 +1864,19 @@ ZEND_FUNCTION(get_declared_interfaces)
static int copy_function_name(zval *zv, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
{
zend_function *func = Z_PTR_P(zv);
zval *internal_ar = va_arg(args, zval *),
*user_ar = va_arg(args, zval *);
zval *internal_ar = va_arg(args, zval *),
*user_ar = va_arg(args, zval *);
zend_bool *disabled = va_arg(args, zend_bool*);

if (hash_key->key == NULL || hash_key->key->val[0] == 0) {
return 0;
}

if (func->type == ZEND_INTERNAL_FUNCTION) {
add_next_index_str(internal_ar, zend_string_copy(hash_key->key));
zend_internal_function *intern = (zend_internal_function*) func;
if ((*disabled) || intern->handler != ZEND_FN(display_disabled_function)) {
add_next_index_str(internal_ar, zend_string_copy(hash_key->key));
}
} else if (func->type == ZEND_USER_FUNCTION) {
add_next_index_str(user_ar, zend_string_copy(hash_key->key));
}
Expand All @@ -1877,21 +1885,22 @@ static int copy_function_name(zval *zv, int num_args, va_list args, zend_hash_ke
}
/* }}} */

/* {{{ proto array get_defined_functions(void)
/* {{{ proto array get_defined_functions(bool disabled = false)
Returns an array of all defined functions */
ZEND_FUNCTION(get_defined_functions)
{
zval internal, user;
zend_bool disabled = 0;

if (zend_parse_parameters_none() == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &disabled) == FAILURE) {
return;
}

array_init(&internal);
array_init(&user);
array_init(return_value);

zend_hash_apply_with_arguments(EG(function_table), copy_function_name, 2, &internal, &user);
zend_hash_apply_with_arguments(EG(function_table), copy_function_name, 3, &internal, &user, &disabled);

zend_hash_str_add_new(Z_ARRVAL_P(return_value), "internal", sizeof("internal")-1, &internal);
zend_hash_str_add_new(Z_ARRVAL_P(return_value), "user", sizeof("user")-1, &user);
Expand Down
Loading

0 comments on commit 49608e0

Please sign in to comment.