Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions Zend/tests/anon/bug-71678-closure.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
--TEST--
Bug #71678 class() extends self/parent/static inside closures
--FILE--
<?php
class Base {

}

class Test extends Base {
static function newParent() {
return function() { return new class() extends parent { }; };
}

static function newSelf() {
return function() { return new class() extends self { }; };
}

static function newStatic() {
return function() { return new class() extends static { }; };
}
}

class Extension extends Test {

}


$parent= Test::newParent()();
var_dump($parent, get_parent_class(get_class($parent)));

$self= Test::newSelf()();
var_dump($self, get_parent_class(get_class($self)));

$self= Extension::newSelf()();
var_dump($self, get_parent_class(get_class($self)));

$ext= Extension::newStatic()();
var_dump($ext, get_parent_class(get_class($ext)));
--EXPECTF--
object(class@%s)#%d (0) {
}
string(4) "Base"
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(9) "Extension"
14 changes: 14 additions & 0 deletions Zend/tests/anon/bug-71678-final-class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Bug #71678 class() extends self with final
--FILE--
<?php
final class Test {

static function newSelf() {
return new class() extends self { };
}
}

Test::newSelf();
--EXPECTF--
Fatal error: Class %s@anonymous may not inherit from final class (Test) in %s on line %d
20 changes: 20 additions & 0 deletions Zend/tests/anon/bug-71678-final-method.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
Bug #71678 class() extends self with final method
--FILE--
<?php
class Test {

static function newSelf() {
return new class() extends self {
function thatsIt() { }
};
}

final function thatsIt() {
// Cannot be overridden!
}
}

Test::newSelf();
--EXPECTF--
Fatal error: Cannot override final method Test::thatsIt() in %s on line %d
20 changes: 20 additions & 0 deletions Zend/tests/anon/bug-71678-overriding.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
Bug #71678 class() extends self overriding with incompatible signature
--FILE--
<?php
class Test {

static function newSelf() {
return new class() extends self {
function thatsIt($pre) { }
};
}

function thatsIt() {
// Base
}
}

Test::newSelf();
--EXPECTF--
Warning: Declaration of %s@anonymous::thatsIt($pre) should be compatible with Test::thatsIt() in %s on line %d
46 changes: 46 additions & 0 deletions Zend/tests/anon/bug-71678-rebound-closure.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
--TEST--
Bug #71678 class() extends self/parent/static inside closures
--FILE--
<?php
class Base {

}

class Test extends Base {
static function newParent() {
return function() { return new class() extends parent { }; };
}

static function newSelf() {
return function() { return new class() extends self { }; };
}

static function newStatic() {
return function() { return new class() extends static { }; };
}
}

class Extension extends Test {

}

$ext= new Extension();

$parent= Test::newParent()->bindTo($ext, $ext)();
var_dump($parent, get_parent_class(get_class($parent)));

$self= Test::newSelf()->bindTo($ext, $ext)();
var_dump($self, get_parent_class(get_class($self)));

$self= Test::newStatic()->bindTo($ext, $ext)();
var_dump($self, get_parent_class(get_class($self)));
--EXPECTF--
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(9) "Extension"
object(class@%s)#%d (0) {
}
string(9) "Extension"
54 changes: 54 additions & 0 deletions Zend/tests/anon/bug-71678-trait.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--TEST--
Bug #71678 class() extends self/parent/static inside traits
--FILE--
<?php
trait Creation {
static function newParent() {
return new class() extends parent { };
}

static function newSelf() {
return new class() extends self { };
}

static function newStatic() {
return new class() extends static { };
}
}

class Base {

}

class Test extends Base {
use Creation;
}

class Extension extends Test {

}

$parent= Test::newParent();
var_dump($parent, get_parent_class(get_class($parent)));

$self= Test::newSelf();
var_dump($self, get_parent_class(get_class($self)));

$self= Extension::newSelf();
var_dump($self, get_parent_class(get_class($self)));

$ext= Extension::newStatic();
var_dump($ext, get_parent_class(get_class($ext)));
--EXPECTF--
object(class@%s)#%d (0) {
}
string(4) "Base"
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(9) "Extension"
62 changes: 62 additions & 0 deletions Zend/tests/anon/bug-71678.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
--TEST--
Bug #71678 class() extends self/parent/static
--FILE--
<?php
class Base {

}

class Test extends Base {
static function newParent() {
return new class() extends parent { };
}

static function newSelf() {
return new class() extends self { };
}

static function newStatic() {
return new class() extends static { };
}
}

class Extension extends Test {

}

$parent= Test::newParent();
var_dump($parent, get_parent_class(get_class($parent)));

$self= Test::newSelf();
var_dump($self, get_parent_class(get_class($self)));

$static= Test::newStatic();
var_dump($static, get_parent_class(get_class($static)));

$parent= Extension::newParent();
var_dump($parent, get_parent_class(get_class($parent)));

$self= Extension::newSelf();
var_dump($self, get_parent_class(get_class($self)));

$static= Extension::newStatic();
var_dump($static, get_parent_class(get_class($static)));
--EXPECTF--
object(class@%s)#%d (0) {
}
string(4) "Base"
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(4) "Base"
object(class@%s)#%d (0) {
}
string(4) "Test"
object(class@%s)#%d (0) {
}
string(9) "Extension"
12 changes: 12 additions & 0 deletions Zend/tests/errmsg_046.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
errmsg: cannot use 'static' as parent class name
--FILE--
<?php

class test extends static {
}

echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d
13 changes: 0 additions & 13 deletions Zend/tests/lsb_006.phpt

This file was deleted.

37 changes: 21 additions & 16 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,8 @@ static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var)
def->opcode == ZEND_DECLARE_INHERITED_CLASS ||
def->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED ||
def->opcode == ZEND_DECLARE_ANON_CLASS ||
def->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS) {
def->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS ||
def->opcode == ZEND_DECLARE_ANON_NEW_CLASS) {
/* classes don't have to be destroyed */
break;
} else if (def->opcode == ZEND_FAST_CALL) {
Expand Down Expand Up @@ -5571,6 +5572,7 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
zend_string *name, *lcname, *import_name = NULL;
zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
zend_op *opline;
uint32_t opcode;
znode declare_node, extends_node;

zend_class_entry *original_ce = CG(active_class_entry);
Expand Down Expand Up @@ -5602,9 +5604,11 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
}

name = zend_new_interned_string(name);
opcode = ZEND_DECLARE_CLASS;
} else {
name = zend_generate_anon_class_name(decl->lex_pos);
lcname = zend_string_tolower(name);
opcode = ZEND_DECLARE_ANON_CLASS;
}
lcname = zend_new_interned_string(lcname);

Expand All @@ -5628,7 +5632,17 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
}

if (extends_ast) {
if (!zend_is_const_default_class_ref(extends_ast)) {
uint32_t fetch_type = zend_get_class_fetch_type_ast(extends_ast);

if (decl->flags & ZEND_ACC_ANON_CLASS) {
if (ZEND_FETCH_CLASS_STATIC == fetch_type) {
opcode = ZEND_DECLARE_ANON_NEW_CLASS;
} else {
opcode = ZEND_DECLARE_ANON_INHERITED_CLASS;
}
} else if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) {
opcode = ZEND_DECLARE_INHERITED_CLASS;
} else {
zend_string *extends_name = zend_ast_get_str(extends_ast);
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use '%s' as class name as it is reserved", ZSTR_VAL(extends_name));
Expand All @@ -5639,31 +5653,22 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */

opline = get_next_op(CG(active_op_array));
zend_make_var_result(&declare_node, opline);
opline->opcode = opcode;

if (extends_ast) {
SET_NODE(opline->op2, &extends_node);
}

GET_NODE(&FC(implementing_class), opline->result);

opline->op1_type = IS_CONST;
LITERAL_STR(opline->op1, lcname);

if (decl->flags & ZEND_ACC_ANON_CLASS) {
if (extends_ast) {
opline->opcode = ZEND_DECLARE_ANON_INHERITED_CLASS;
SET_NODE(opline->op2, &extends_node);
} else {
opline->opcode = ZEND_DECLARE_ANON_CLASS;
}

zend_hash_update_ptr(CG(class_table), lcname, ce);
} else {
zend_string *key;

if (extends_ast) {
opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
SET_NODE(opline->op2, &extends_node);
} else {
opline->opcode = ZEND_DECLARE_CLASS;
}

key = zend_build_runtime_definition_key(lcname, decl->lex_pos);
/* RTD key is placed after lcname literal in op1 */
zend_add_literal_string(CG(active_op_array), &key);
Expand Down
Loading