From 2ba15bd7683bca7e4ed40c74cb4d3c7db6085d8c Mon Sep 17 00:00:00 2001 From: Davey Shafik <me@daveyshafik.com> Date: Wed, 28 Mar 2012 15:40:01 -0400 Subject: [PATCH] Add support for checking trait usage to class_uses() --- ext/spl/php_spl.c | 29 +++++++++-- ext/spl/tests/class_uses_basic3.phpt | 30 ++++++++++++ ext/spl/tests/class_uses_basic4.phpt | 72 ++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 ext/spl/tests/class_uses_basic3.phpt create mode 100644 ext/spl/tests/class_uses_basic4.phpt diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index cd0086626fc7d..35df18dc14737 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -156,9 +156,13 @@ PHP_FUNCTION(class_uses) { zval *obj; zend_bool autoload = 1; + char *trait_name = NULL; + int trait_name_len; + int i; zend_class_entry *ce; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) { + zend_class_entry **trait_ce; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bs", &obj, &autoload, &trait_name, &trait_name_len) == FAILURE) { RETURN_FALSE; } if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) { @@ -173,9 +177,24 @@ PHP_FUNCTION(class_uses) } else { ce = Z_OBJCE_P(obj); } - - array_init(return_value); - spl_add_traits(return_value, ce, 1, ZEND_ACC_TRAIT TSRMLS_CC); + + if (trait_name == NULL) { + array_init(return_value); + spl_add_traits(return_value, ce, 1, ZEND_ACC_TRAIT TSRMLS_CC); + } else { + if (zend_lookup_class_ex(trait_name, trait_name_len, NULL, 0, &trait_ce TSRMLS_CC) != FAILURE) { + while (ce) { + for (i=0; i < ce->num_traits; i++) { + if (ce->traits[i] == *trait_ce) { + RETURN_TRUE; + } + } + ce = ce->parent; + } + } + + RETURN_FALSE; + } } /* }}} */ diff --git a/ext/spl/tests/class_uses_basic3.phpt b/ext/spl/tests/class_uses_basic3.phpt new file mode 100644 index 0000000000000..a49e905cac81e --- /dev/null +++ b/ext/spl/tests/class_uses_basic3.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: Test class_implements() function : basic +--FILE-- +<?php +/* Prototype : array class_uses(mixed what [, bool autoload ], [, string trait_name]) + * Description: Return all traits used by a class or check if a trait is used + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_uses() : basic ***\n"; + + +trait foo { } +class bar { use foo; } + +var_dump(class_uses(new bar, false, 'foo')); +var_dump(class_uses('bar', false, 'foo')); +var_dump(class_uses(new bar, false, 'bar')); +var_dump(class_uses(new bar, false, 'bat')); + +?> +===DONE=== +--EXPECT-- +*** Testing class_uses() : basic *** +bool(true) +bool(true) +bool(false) +bool(false) +===DONE=== diff --git a/ext/spl/tests/class_uses_basic4.phpt b/ext/spl/tests/class_uses_basic4.phpt new file mode 100644 index 0000000000000..b6213dcaa2d14 --- /dev/null +++ b/ext/spl/tests/class_uses_basic4.phpt @@ -0,0 +1,72 @@ +--TEST-- +SPL: Test class_uses() function : basic +--FILE-- +<?php +/* Prototype : array class_uses(mixed what [, bool autoload ], [, string trait_name]) + * Description: Return all traits used by a class or check if a trait is used + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_uses() : basic ***\n"; + + +trait foo { } +class fooUser { use foo; } + +trait bar { } +class barUser { use bar; } + +class foobarUser { use foo, bar; } + +/** There is no semantics for traits in the inheritance chain. + Traits are flattend into a class, and that semantics is nothing + like a type, or interface, and thus, not propergated. */ +class fooViaBarUser extends barUser { use foo; } + +class fooExtended extends fooUser {} + +var_dump(class_uses(new foobarUser, false, 'foo')); +var_dump(class_uses(new foobarUser, false, 'bar')); +var_dump(class_uses(new foobarUser, false, 'baz')); +var_dump(class_uses('foobarUser', false, 'foo')); +var_dump(class_uses('foobarUser', false, 'bar')); +var_dump(class_uses('foobarUser', false, 'baz')); + +var_dump(class_uses(new fooViaBarUser, false, 'foo')); +var_dump(class_uses(new fooViaBarUser, false, 'bar')); +var_dump(class_uses(new fooViaBarUser, false, 'baz')); +var_dump(class_uses('fooViaBarUser', false, 'foo')); +var_dump(class_uses('fooViaBarUser', false, 'bar')); +var_dump(class_uses('fooViaBarUser', false, 'baz')); + +var_dump(class_uses(new fooExtended, false, 'foo')); +var_dump(class_uses(new fooExtended, false, 'bar')); +var_dump(class_uses(new fooExtended, false, 'baz')); +var_dump(class_uses('fooExtended', false, 'foo')); +var_dump(class_uses('fooExtended', false, 'bar')); +var_dump(class_uses('fooExtended', false, 'baz')); + +?> +===DONE=== +--EXPECT-- +*** Testing class_uses() : basic *** +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +bool(false) +bool(false) +===DONE===