Skip to content

Commit 3d66f17

Browse files
authored
Merge pull request #268 from joelwurtz/feat/iterator
feat(iterator): add helper for zend_object_iterator and iterable type
2 parents b876077 + f449f4e commit 3d66f17

File tree

15 files changed

+818
-83
lines changed

15 files changed

+818
-83
lines changed

allowed_bindings.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ bind! {
9494
zend_internal_arg_info,
9595
zend_is_callable,
9696
zend_is_identical,
97+
zend_is_iterable,
9798
zend_long,
9899
zend_lookup_class_ex,
99100
zend_module_entry,
@@ -163,6 +164,7 @@ bind! {
163164
IS_UNDEF,
164165
IS_VOID,
165166
IS_PTR,
167+
IS_ITERABLE,
166168
MAY_BE_ANY,
167169
MAY_BE_BOOL,
168170
PHP_INI_USER,

docsrs_bindings.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub const IS_RESOURCE: u32 = 9;
9797
pub const IS_REFERENCE: u32 = 10;
9898
pub const IS_CONSTANT_AST: u32 = 11;
9999
pub const IS_CALLABLE: u32 = 12;
100+
pub const IS_ITERABLE: u32 = 13;
100101
pub const IS_VOID: u32 = 14;
101102
pub const IS_MIXED: u32 = 16;
102103
pub const IS_INDIRECT: u32 = 12;
@@ -1658,6 +1659,9 @@ extern "C" {
16581659
named_params: *mut HashTable,
16591660
);
16601661
}
1662+
extern "C" {
1663+
pub fn zend_is_iterable(iterable: *const zval) -> bool;
1664+
}
16611665
pub const _zend_expected_type_Z_EXPECTED_LONG: _zend_expected_type = 0;
16621666
pub const _zend_expected_type_Z_EXPECTED_LONG_OR_NULL: _zend_expected_type = 1;
16631667
pub const _zend_expected_type_Z_EXPECTED_BOOL: _zend_expected_type = 2;

guide/src/types/iterable.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# `Iterable`
2+
3+
`Iterable`s are represented either by an `array` or `Traversable` type.
4+
5+
| `T` parameter | `&T` parameter | `T` Return type | `&T` Return type | PHP representation |
6+
|---------------|----------------|-----------------| ---------------- |----------------------------------|
7+
| Yes | No | No | No | `ZendHashTable` or `ZendIterator` |
8+
9+
Converting from a zval to a `Iterable` is valid when the value is either an array or an object
10+
that implements the `Traversable` interface. This means that any value that can be used in a
11+
`foreach` loop can be converted into a `Iterable`.
12+
13+
## Rust example
14+
15+
```rust,no_run
16+
# #![cfg_attr(windows, feature(abi_vectorcall))]
17+
# extern crate ext_php_rs;
18+
# use ext_php_rs::prelude::*;
19+
# use ext_php_rs::types::Iterable;
20+
#[php_function]
21+
pub fn test_iterable(mut iterable: Iterable) {
22+
for (k, v) in iterable.iter().expect("cannot rewind iterator") {
23+
println!("k: {} v: {}", k.string().unwrap(), v.string().unwrap());
24+
}
25+
}
26+
# fn main() {}
27+
```
28+
29+
## PHP example
30+
31+
```php
32+
<?php
33+
34+
$generator = function() {
35+
yield 'hello' => 'world';
36+
yield 'rust' => 'php';
37+
};
38+
39+
$array = [
40+
'hello' => 'world',
41+
'rust' => 'php',
42+
];
43+
44+
test_iterable($generator());
45+
test_iterable($array);
46+
```
47+
48+
Output:
49+
50+
```text
51+
k: hello v: world
52+
k: rust v: php
53+
k: hello v: world
54+
k: rust v: php
55+
```

guide/src/types/iterator.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# `ZendIterator`
2+
3+
`ZendIterator`s are represented by the `Traversable` type.
4+
5+
| `T` parameter | `&T` parameter | `T` Return type | `&T` Return type | PHP representation |
6+
|---------------| -------------- |-----------------| ---------------- | ------------------ |
7+
| No | Yes | No | No | `ZendIterator` |
8+
9+
Converting from a zval to a `ZendIterator` is valid when there is an associated iterator to
10+
the variable. This means that any value, at the exception of an `array`, that can be used in
11+
a `foreach` loop can be converted into a `ZendIterator`. As an example, a `Generator` can be
12+
used but also a the result of a `query` call with `PDO`.
13+
14+
If you want a more universal `iterable` type that also supports arrays, see [Iterable](./iterable.md).
15+
16+
## Rust example
17+
18+
```rust,no_run
19+
# #![cfg_attr(windows, feature(abi_vectorcall))]
20+
# extern crate ext_php_rs;
21+
# use ext_php_rs::prelude::*;
22+
# use ext_php_rs::types::ZendIterator;
23+
#[php_function]
24+
pub fn test_iterator(iterator: &mut ZendIterator) {
25+
for (k, v) in iterator.iter().expect("cannot rewind iterator") {
26+
// Note that the key can be anything, even an object
27+
// when iterating over Traversables!
28+
println!("k: {} v: {}", k.string().unwrap(), v.string().unwrap());
29+
}
30+
}
31+
# fn main() {}
32+
```
33+
34+
## PHP example
35+
36+
```php
37+
<?php
38+
39+
$generator = function() {
40+
yield 'hello' => 'world';
41+
yield 'rust' => 'php';
42+
};
43+
44+
test_iterator($generator());
45+
```
46+
47+
Output:
48+
49+
```text
50+
k: hello v: world
51+
k: rust v: php
52+
```

src/describe/stub.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ impl ToStub for DataType {
172172
DataType::Reference => "reference",
173173
DataType::Callable => "callable",
174174
DataType::Bool => "bool",
175+
DataType::Iterable => "iterable",
175176
_ => "mixed",
176177
}
177178
)

src/flags.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use crate::ffi::{
88
CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, E_COMPILE_ERROR,
99
E_COMPILE_WARNING, E_CORE_ERROR, E_CORE_WARNING, E_DEPRECATED, E_ERROR, E_NOTICE, E_PARSE,
1010
E_RECOVERABLE_ERROR, E_STRICT, E_USER_DEPRECATED, E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING,
11-
E_WARNING, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE, IS_INDIRECT, IS_LONG,
12-
IS_MIXED, IS_NULL, IS_OBJECT, IS_PTR, IS_REFERENCE, IS_RESOURCE, IS_STRING, IS_TRUE,
13-
IS_TYPE_COLLECTABLE, IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, PHP_INI_ALL, PHP_INI_PERDIR,
14-
PHP_INI_SYSTEM, PHP_INI_USER, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS,
11+
E_WARNING, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE, IS_INDIRECT,
12+
IS_ITERABLE, IS_LONG, IS_MIXED, IS_NULL, IS_OBJECT, IS_PTR, IS_REFERENCE, IS_RESOURCE,
13+
IS_STRING, IS_TRUE, IS_TYPE_COLLECTABLE, IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, PHP_INI_ALL,
14+
PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_USER, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS,
1515
ZEND_ACC_CALL_VIA_TRAMPOLINE, ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED,
1616
ZEND_ACC_CTOR, ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING,
1717
ZEND_ACC_FAKE_CLOSURE, ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK,
@@ -49,6 +49,7 @@ bitflags! {
4949
const ConstantExpression = IS_CONSTANT_AST;
5050
const Void = IS_VOID;
5151
const Ptr = IS_PTR;
52+
const Iterable = IS_ITERABLE;
5253

5354
const InternedStringEx = Self::String.bits();
5455
const StringEx = Self::String.bits() | Self::RefCounted.bits();
@@ -237,6 +238,7 @@ pub enum DataType {
237238
Double,
238239
String,
239240
Array,
241+
Iterable,
240242
Object(Option<&'static str>),
241243
Resource,
242244
Reference,
@@ -277,6 +279,7 @@ impl DataType {
277279
DataType::Mixed => IS_MIXED,
278280
DataType::Bool => _IS_BOOL,
279281
DataType::Ptr => IS_PTR,
282+
DataType::Iterable => IS_ITERABLE,
280283
}
281284
}
282285
}
@@ -383,6 +386,7 @@ impl Display for DataType {
383386
DataType::Mixed => write!(f, "Mixed"),
384387
DataType::Ptr => write!(f, "Pointer"),
385388
DataType::Indirect => write!(f, "Indirect"),
389+
DataType::Iterable => write!(f, "Iterable"),
386390
}
387391
}
388392
}

0 commit comments

Comments
 (0)