Skip to content

[DRAFT] [WIP] Initial zend_class_alias #18789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add #[ClassAlias]
  • Loading branch information
DanielEScherzer committed Jun 9, 2025
commit e1a37a8b7b75cba0527265479942ecba1c592886
11 changes: 11 additions & 0 deletions Zend/tests/attributes/class_alias/parameter_invalid.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Alias name must be valid
--FILE--
<?php

#[ClassAlias('never')]
class Demo {}

?>
--EXPECTF--
Fatal error: Cannot use "never" as a class alias as it is reserved in %s on line %d
11 changes: 11 additions & 0 deletions Zend/tests/attributes/class_alias/parameter_nonstring.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Parameter must be a string
--FILE--
<?php

#[ClassAlias([])]
class Demo {}

?>
--EXPECTF--
Fatal error: ClassAlias::__construct(): Argument #1 ($alias) must be of type string, array given in %s on line %d
15 changes: 15 additions & 0 deletions Zend/tests/attributes/class_alias/parameter_required.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Parameter is required
--FILE--
<?php

#[ClassAlias]
class Demo {}

?>
--EXPECTF--
Fatal error: Uncaught ArgumentCountError: ClassAlias::__construct() expects exactly 1 argument, 0 given in %s:%d
Stack trace:
#0 %s(%d): ClassAlias->__construct()
#1 {main}
thrown in %s on line %d
11 changes: 11 additions & 0 deletions Zend/tests/attributes/class_alias/redeclaration_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Cannot redeclare an existing class
--FILE--
<?php

#[ClassAlias('Attribute')]
class Demo {}

?>
--EXPECTF--
Fatal error: Unable to declare alias 'Attribute' for 'Demo' in %s on line %d
25 changes: 25 additions & 0 deletions Zend/tests/attributes/class_alias/repeated_attribute.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
Attribute can be repeated
--FILE--
<?php

#[ClassAlias('First')]
#[ClassAlias('Second')]
class Demo {}

var_dump( class_exists( 'First' ) );
var_dump( class_exists( 'Second' ) );

$obj1 = new First();
var_dump( $obj1 );

$obj2 = new Second();
var_dump( $obj2 );
?>
--EXPECTF--
bool(true)
bool(true)
object(Demo)#%d (0) {
}
object(Demo)#%d (0) {
}
11 changes: 11 additions & 0 deletions Zend/tests/attributes/class_alias/target_validation.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Can only be used on classes
--FILE--
<?php

#[ClassAlias]
function demo() {}

?>
--EXPECTF--
Fatal error: Attribute "ClassAlias" cannot target function (allowed targets: class) in %s on line %d
17 changes: 17 additions & 0 deletions Zend/tests/attributes/class_alias/working_example.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Working usage
--FILE--
<?php

#[ClassAlias('Other')]
class Demo {}

var_dump( class_exists( 'Other' ) );

$obj = new Other();
var_dump( $obj );
?>
--EXPECTF--
bool(true)
object(Demo)#%d (0) {
}
63 changes: 63 additions & 0 deletions Zend/zend_attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ ZEND_API zend_class_entry *zend_ce_sensitive_parameter_value;
ZEND_API zend_class_entry *zend_ce_override;
ZEND_API zend_class_entry *zend_ce_deprecated;
ZEND_API zend_class_entry *zend_ce_nodiscard;
ZEND_API zend_class_entry *zend_ce_class_alias;

static zend_object_handlers attributes_object_handlers_sensitive_parameter_value;

Expand Down Expand Up @@ -95,6 +96,46 @@ static void validate_allow_dynamic_properties(
scope->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
}

static void validate_class_alias(
zend_attribute *attr, uint32_t target, zend_class_entry *scope)
{
zval alias_obj;
ZVAL_UNDEF(&alias_obj);
zend_result result = zend_get_attribute_object(
&alias_obj,
zend_ce_class_alias,
attr,
scope,
scope->info.user.filename
);
if (result == FAILURE) {
ZEND_ASSERT(EG(exception));
return;
}

zval *alias_name = zend_read_property(
zend_ce_class_alias,
Z_OBJ(alias_obj),
ZEND_STRL("alias"),
false,
NULL
);
result = zend_register_class_alias_ex(
Z_STRVAL_P(alias_name),
Z_STRLEN_P(alias_name),
scope,
false
);
if (result == FAILURE) {
zend_error_noreturn(E_ERROR, "Unable to declare alias '%s' for '%s'",
Z_STRVAL_P(alias_name),
ZSTR_VAL(scope->name)
);
}
zval_ptr_dtor(alias_name);
zval_ptr_dtor(&alias_obj);
}

ZEND_METHOD(Attribute, __construct)
{
zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
Expand Down Expand Up @@ -217,6 +258,24 @@ ZEND_METHOD(NoDiscard, __construct)
}
}

ZEND_METHOD(ClassAlias, __construct)
{
zend_string *alias = NULL;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(alias)
ZEND_PARSE_PARAMETERS_END();

zval value;
ZVAL_STR(&value, alias);
zend_update_property(zend_ce_class_alias, Z_OBJ_P(ZEND_THIS), ZEND_STRL("alias"), &value);

/* The assignment might fail due to 'readonly'. */
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
}

static zend_attribute *get_attribute(HashTable *attributes, zend_string *lcname, uint32_t offset)
{
if (attributes) {
Expand Down Expand Up @@ -548,6 +607,10 @@ void zend_register_attribute_ce(void)

zend_ce_nodiscard = register_class_NoDiscard();
attr = zend_mark_internal_attribute(zend_ce_nodiscard);

zend_ce_class_alias = register_class_ClassAlias();
attr = zend_mark_internal_attribute(zend_ce_class_alias);
attr->validator = validate_class_alias;
}

void zend_attributes_shutdown(void)
Expand Down
11 changes: 11 additions & 0 deletions Zend/zend_attributes.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,14 @@ final class NoDiscard

public function __construct(?string $message = null) {}
}

/**
* @strict-properties
*/
#[Attribute(Attribute::TARGET_CLASS|Attribute::IS_REPEATABLE)]
final class ClassAlias
{
public readonly string $alias;

public function __construct(string $alias) {}
}
35 changes: 34 additions & 1 deletion Zend/zend_attributes_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.