Implement ArrayAccess. Fix config.m4, .travis.yml. Update stubs.

master
CismonX 5 years ago
parent dc4a1546eb
commit 7b98857eff
  1. 3
      .travis.yml
  2. 8
      config.m4
  3. 4
      src/collections.c
  4. 14
      src/collections_me.c
  5. 68
      src/collections_methods.c
  6. 10
      src/php_collections.h
  7. 4
      src/php_collections_me.h
  8. 12
      stubs/Collection.php
  9. 4
      tests/012-countable.phpt
  10. 19
      tests/013-array-access.phpt

@ -14,5 +14,4 @@ script:
- phpize
- ./configure
- make
- echo $'n\n' | make test
- sudo make install
- make test

@ -1,15 +1,7 @@
PHP_ARG_ENABLE(collections, for collections support,
[ --enable-collections Enable collections support])
PHP_ARG_ENABLE(collections-debug, for debug support,
[ --enable-collections-debug Compile with debug symbols], no, no)
if test "$PHP_COLLECTIONS" != "no"; then
if test "$PHP_COLLECTIONS_DEBUG" != "no"; then
CFLAGS="-g -O0"
else
CFLAGS="-O2"
fi
COLLECTIONS_SRC="src/collections.c
src/collections_me.c
src/collections_methods.c"

@ -40,6 +40,10 @@ PHP_MINIT_FUNCTION(collections)
collection_handlers = (zend_object_handlers*)emalloc(sizeof(zend_object_handlers));
memcpy(collection_handlers, &std_object_handlers, sizeof(zend_object_handlers));
collection_handlers->count_elements = count_collection;
collection_handlers->unset_dimension = collection_offset_unset;
collection_handlers->write_dimension = collection_offset_set;
collection_handlers->read_dimension = collection_offset_get;
collection_handlers->has_dimension = collection_offset_exists;
zend_class_entry pair_ce;
INIT_CLASS_ENTRY_EX(pair_ce, "Pair", sizeof "Pair" - 1, pair_methods);
collections_pair_ce = zend_register_internal_class(&pair_ce);

@ -6,7 +6,6 @@
#include <php.h>
#include "php_collections.h"
#include "php_collections_me.h"
ZEND_BEGIN_ARG_INFO(action_arginfo, 0)
@ -40,10 +39,6 @@ ZEND_BEGIN_ARG_INFO(initial_operation_arginfo, 0)
ZEND_ARG_CALLABLE_INFO(0, operation, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(key_arginfo, 0)
ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(keys_arginfo, 0)
ZEND_ARG_INFO(0, keys)
ZEND_END_ARG_INFO()
@ -86,6 +81,10 @@ ZEND_BEGIN_ARG_INFO(associate_by_to_arginfo, 0)
ZEND_ARG_CALLABLE_INFO(0, key_selector, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(contains_key_arginfo, 0)
ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(copy_of_arginfo, 0)
ZEND_ARG_TYPE_INFO(0, new_size, IS_LONG, 0)
ZEND_END_ARG_INFO()
@ -132,7 +131,7 @@ const zend_function_entry collection_methods[] = {
PHP_ME(Collection, associateByTo, associate_by_to_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, average, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsAll, other_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsKey, key_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsKey, contains_key_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, containsValue, element_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, copyOf, copy_of_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, copyOfRange, copy_of_range_arginfo, ZEND_ACC_PUBLIC)
@ -189,9 +188,6 @@ const zend_function_entry collection_methods[] = {
PHP_ME(Collection, minusValues, elements_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, minusValuesAssign, elements_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, none, predicate_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, offsetUnset, key_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, offsetSet, key_value_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, offsetExists, key_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, onEach, action_arginfo, ZEND_ACC_PUBLIC)
PHP_ME(Collection, orEmpty, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Collection, partition, predicate_arginfo, ZEND_ACC_PUBLIC)

@ -111,6 +111,54 @@ int count_collection(zval* obj, zend_long* count)
return SUCCESS;
}
int collection_offset_exists(zval* object, zval* offset, int check_empty)
{
zval rv;
zval* current = COLLECTION_FETCH(object);
if (check_empty)
return zend_hash_num_elements(Z_ARRVAL_P(current)) == 0;
if (Z_TYPE_P(offset) == IS_LONG)
return zend_hash_index_exists(Z_ARRVAL_P(current), Z_LVAL_P(offset));
if (Z_TYPE_P(offset) == IS_STRING)
return zend_hash_exists(Z_ARRVAL_P(current), Z_STR_P(offset));
return 0;
}
void collection_offset_set(zval* object, zval* offset, zval* value)
{
zval rv;
zval* current = COLLECTION_FETCH(object);
if (Z_TYPE_P(offset) == IS_LONG)
zend_hash_index_update(Z_ARRVAL_P(current), Z_LVAL_P(offset), value);
else if (Z_TYPE_P(offset) == IS_STRING)
zend_hash_update(Z_ARRVAL_P(current), Z_STR_P(offset), value);
}
zval* collection_offset_get(zval* object, zval* offset, int type, zval* retval)
{
// Note that we don't handler type. So don't do any fancy things with Collection
// such as fetching a reference of a value, etc.
zval rv;
zval* current = COLLECTION_FETCH(object);
zval* found = NULL;
if (Z_TYPE_P(offset) == IS_LONG)
found = zend_hash_index_find(Z_ARRVAL_P(current), Z_LVAL_P(offset));
else if (Z_TYPE_P(offset) == IS_STRING)
found = zend_hash_find(Z_ARRVAL_P(current), Z_STR_P(offset));
ZVAL_COPY(retval, found);
return retval;
}
void collection_offset_unset(zval* object, zval* offset)
{
zval rv;
zval* current = COLLECTION_FETCH(object);
if (Z_TYPE_P(offset) == IS_LONG)
zend_hash_index_del(Z_ARRVAL_P(current), Z_LVAL_P(offset));
else if (Z_TYPE_P(offset) == IS_STRING)
zend_hash_del(Z_ARRVAL_P(current), Z_STR_P(offset));
}
PHP_METHOD(Collection, __construct) {}
PHP_METHOD(Collection, addAll)
@ -702,26 +750,6 @@ PHP_METHOD(Collection, none)
}
PHP_METHOD(Collection, offsetUnset)
{
}
PHP_METHOD(Collection, offsetSet)
{
}
PHP_METHOD(Collection, offsetGet)
{
}
PHP_METHOD(Collection, offsetExists)
{
}
PHP_METHOD(Collection, onEach)
{

@ -20,9 +20,9 @@ extern zend_module_entry collections_module_entry;
#define PHP_COLLECTIONS_API
#endif
#if PHP_VERSION_ID < 70300
#define GC_ADDREF(p) ++GC_REFCOUNT(p)
#define GC_DELREF(p) --GC_REFCOUNT(p)
#if PHP_VERSION_ID < 70300
#define GC_ADDREF(p) ++GC_REFCOUNT(p)
#define GC_DELREF(p) --GC_REFCOUNT(p)
#endif
extern zend_string* collection_property_name;
@ -35,6 +35,10 @@ extern PHP_COLLECTIONS_API zend_class_entry* collections_pair_ce;
extern zend_object_handlers* collection_handlers;
int count_collection(zval* obj, zend_long* count);
int collection_offset_exists(zval* object, zval* offset, int check_empty);
void collection_offset_set(zval* object, zval* offset, zval* value);
zval* collection_offset_get(zval* object, zval* offset, int type, zval* rv);
void collection_offset_unset(zval* object, zval* offset);
extern const zend_function_entry collection_methods[];
extern const zend_function_entry pair_methods[];

@ -74,10 +74,6 @@ PHP_METHOD(Collection, minusKeysAssign);
PHP_METHOD(Collection, minusValues);
PHP_METHOD(Collection, minusValuesAssign);
PHP_METHOD(Collection, none);
PHP_METHOD(Collection, offsetUnset);
PHP_METHOD(Collection, offsetSet);
PHP_METHOD(Collection, offsetGet);
PHP_METHOD(Collection, offsetExists);
PHP_METHOD(Collection, onEach);
PHP_METHOD(Collection, orEmpty);
PHP_METHOD(Collection, partition);

@ -581,21 +581,33 @@ class Collection implements ArrayAccess, Countable
function none($predicate) {}
/**
* This method is implemented in handlers.unset_dimension.
* There's no method with name 'offsetUnset'.
*
* @internal
*/
function offsetUnset($key) {}
/**
* This method is implemented in handlers.write_dimension.
* There's no method with name 'offsetSet'.
*
* @internal
*/
function offsetSet($key, $value) {}
/**
* This method is implemented in handlers.read_dimension.
* There's no method with name 'offsetGet'.
*
* @internal
*/
function offsetGet($key) {}
/**
* This method is implemented in handlers.has_dimension.
* There's no method with name 'offsetExists'.
*
* @internal
*/
function offsetExists($key) {}

@ -1,5 +1,5 @@
--TEST--
Test Collection::count() and countable interface.
Test Collection::count() and implementation of interface Countable.
--FILE--
<?php
$array = [1, 2, 3, 4, 5, 6];
@ -7,6 +7,6 @@ $collection = Collection::init($array);
if ($collection->count() != count($array))
echo 'Collection::count() failed.', PHP_EOL;
if (count($collection) != count($array))
echo 'Test for countable interface failed.', PHP_EOL;
echo 'Test for handlers.count_elements failed.', PHP_EOL;
?>
--EXPECT--

@ -0,0 +1,19 @@
--TEST--
Test implementation of interface ArrayAccess.
--FILE--
<?php
$array = ['a' => 'b', 'c' => 'd', 'e' => ['f' => 'g']];
$collection = Collection::init($array);
$collection['a'] = 'foo';
$collection['h'] = 'bar';
unset($collection['c']);
if (empty($collection) || isset($collection['t']) || !isset($collection['e']))
echo 'Test for handlers.has_dimension failed.', PHP_EOL;
if ($collection['e']['f'] != 'g')
echo 'Test for handlers.read_dimension failed.', PHP_EOL;
if ($collection['a'] != 'foo' || $collection['h'] != 'bar')
echo 'Test for handlers.write_dimension failed.', PHP_EOL;
if (isset($collection['c']))
echo 'Test for handlers.unset_dimension failed.', PHP_EOL;
?>
--EXPECT--