Skip to content

Commit 8d6e46d

Browse files
committed
[odb_backend] implement foreach callback. slightly tricky
1 parent 50d095b commit 8d6e46d

File tree

5 files changed

+123
-7
lines changed

5 files changed

+123
-7
lines changed

example/odb_backend.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@ class Pool
6060

6161
},
6262
"foreach" => function($foreach_cb, &$payload) { // this payload was passed by git_odb_foreach callback.
63+
echo "\e[32m# foreach (iterate all backends)\e[m\n";
6364
foreach (Pool::$pool as $oid => $value) {
6465
$retval = $foreach_cb($oid, $payload);
6566
if ($retval == GIT_EUSER) {
6667
return $retval;
6768
}
6869
}
70+
return 0;
6971
},
7072
"writepack" => function() {
7173

@@ -91,9 +93,8 @@ class Pool
9193
$obj = git_odb_read_prefix($odb, substr($oid, 0, 10));
9294
var_dump($obj);
9395

94-
9596
$payload = array();
9697
git_odb_foreach($odb, function($oid, &$payload) {
97-
echo $oid . PHP_EOL;
98+
echo ".";
9899
}, $payload);
99100
exit;

odb.c

+60-5
Original file line numberDiff line numberDiff line change
@@ -933,28 +933,84 @@ static int php_git2_odb_backend_exists(git_odb_backend *backend, const git_oid *
933933
return !retval;
934934

935935
}
936+
937+
static const zend_arg_info arginfo_git_odb_backend_foreach_callback[] = {
938+
ZEND_ARG_INFO(0, oid)
939+
ZEND_ARG_INFO(1, payload)
940+
};
941+
942+
static void git_ex_cb(INTERNAL_FUNCTION_PARAMETERS)
943+
{
944+
zval *payload, *this = getThis();
945+
php_git2_odb_backend_foreach_callback *_callback;
946+
char *oid;
947+
int oid_len, retval = 0;
948+
git_oid _oid;
949+
950+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
951+
"sz", &oid, &oid_len, &payload) == FAILURE) {
952+
return;
953+
}
954+
955+
if (git_oid_fromstrn(&_oid, oid, oid_len) != GIT_OK) {
956+
return;
957+
}
958+
959+
_callback = (php_git2_odb_backend_foreach_callback*)zend_object_store_get_object(this TSRMLS_CC);
960+
_callback->payload->payload = payload;
961+
retval = _callback->callback(&_oid, _callback->payload);
962+
RETURN_LONG(retval);
963+
}
964+
936965
static int php_git2_odb_backend_foreach(git_odb_backend *backend, git_odb_foreach_cb cb, void *data)
937966
{
938967
php_git2_t *result;
939968
php_git2_odb_backend *php_backend = (php_git2_odb_backend*)backend;
940-
zval *param_callback = NULL, *retval_ptr = NULL, *param_payload = (zval*)data;
969+
zval *param_callback = NULL, *callback = NULL, *retval_ptr = NULL, *param_payload = (zval*)data;
941970
php_git2_multi_cb_t *p = php_backend->multi;
971+
zend_function function = {0};
972+
php_git2_odb_backend_foreach_callback *_callback;
973+
php_git2_cb_t *__cb = (php_git2_cb_t*)data;
942974
int i = 0, retval = 0;
943975
GIT2_TSRMLS_SET(p->tsrm_ls);
944976

977+
MAKE_STD_ZVAL(callback);
978+
object_init_ex(callback, php_git2_odb_backend_foreach_callback_class_entry);
979+
_callback = (php_git2_odb_backend_foreach_callback*)zend_object_store_get_object(callback TSRMLS_CC);
980+
_callback->callback = cb;
981+
_callback->payload = __cb;
982+
Z_ADDREF_P(callback);
983+
984+
function.type = ZEND_INTERNAL_FUNCTION;
985+
function.common.function_name = "callback";
986+
function.common.fn_flags = ZEND_ACC_CLOSURE;
987+
function.common.num_args = 2;
988+
function.common.required_num_args = 2;
989+
function.common.arg_info = &arginfo_git_odb_backend_foreach_callback;
990+
function.common.scope = php_git2_odb_backend_foreach_callback_class_entry;
991+
function.internal_function.type = ZEND_INTERNAL_FUNCTION;
992+
function.internal_function.scope = php_git2_odb_backend_foreach_callback_class_entry;
993+
function.internal_function.fn_flags = ZEND_ACC_CLOSURE;
994+
function.internal_function.handler = git_ex_cb;
995+
function.internal_function.module = &git2_module_entry;
996+
function.internal_function.num_args = 2;
997+
function.internal_function.required_num_args = 2;
998+
function.internal_function.arg_info = &arginfo_git_odb_backend_foreach_callback;
999+
9451000
MAKE_STD_ZVAL(param_callback);
946-
// TODO(chobie): wrap git_odb_foreach_cb with closure
947-
// see zend_create_closure
1001+
zend_create_closure(param_callback, &function, php_git2_odb_backend_foreach_callback_class_entry, callback TSRMLS_CC);
1002+
Z_ADDREF_P(__cb->payload);
9481003

9491004
if (php_git2_call_function_v(&p->callbacks[6].fci, &p->callbacks[6].fcc TSRMLS_CC, &retval_ptr, 2,
950-
&param_callback, &param_payload)) {
1005+
&param_callback, &__cb->payload)) {
9511006
return GIT_EUSER;
9521007
}
9531008

9541009
retval = Z_LVAL_P(retval_ptr);
9551010
zval_ptr_dtor(&retval_ptr);
9561011
return retval;
9571012
}
1013+
9581014
static void php_git2_odb_backend_free(git_odb_backend *_backend)
9591015
{
9601016
}
@@ -1012,7 +1068,6 @@ PHP_FUNCTION(git_odb_backend_new)
10121068
php_git2_fcall_info_wrapper2(tmp, &foreach_fci, &foreach_fcc TSRMLS_CC);
10131069
}
10141070

1015-
10161071
Z_ADDREF_P(callbacks);
10171072
php_git2_multi_cb_init(&backend->multi, callbacks TSRMLS_CC, 8,
10181073
&read_fci, &read_fcc,

php_git2.c

+23
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070

7171
int git2_resource_handle;
7272

73+
zend_class_entry *php_git2_odb_backend_foreach_callback_class_entry;
74+
7375
void static destruct_git2(zend_rsrc_list_entry *rsrc TSRMLS_DC)
7476
{
7577
php_git2_t *resource = (php_git2_t *)rsrc->ptr;
@@ -1016,10 +1018,31 @@ static PHP_GSHUTDOWN_FUNCTION(git2)
10161018
{
10171019
}
10181020

1021+
1022+
static void php_git2_odb_backend_foreach_callback_free_storage(php_git2_odb_backend_foreach_callback *object TSRMLS_DC)
1023+
{
1024+
zend_object_std_dtor(&object->zo TSRMLS_CC);
1025+
efree(object);
1026+
}
1027+
1028+
zend_object_value php_git2_odb_backend_foreach_callback_new(zend_class_entry *ce TSRMLS_DC)
1029+
{
1030+
zend_object_value retval;
1031+
PHP_GIT2_STD_CREATE_OBJECT(php_git2_odb_backend_foreach_callback);
1032+
return retval;
1033+
}
1034+
10191035
PHP_MINIT_FUNCTION(git2)
10201036
{
1037+
zend_class_entry ce;
10211038
REGISTER_INI_ENTRIES();
10221039

1040+
1041+
INIT_CLASS_ENTRY(ce, "Git2ODBBackendForeachCallback", 0);
1042+
php_git2_odb_backend_foreach_callback_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
1043+
zend_register_class_alias_ex(ZEND_NS_NAME("Git2\\ODB\\Backend", "ForeachCallback"), sizeof(ZEND_NS_NAME("Git2\\ODB\\Backend", "ForeachCallback"))-1, php_git2_odb_backend_foreach_callback_class_entry TSRMLS_CC);
1044+
php_git2_odb_backend_foreach_callback_class_entry->create_object = php_git2_odb_backend_foreach_callback_new;
1045+
10231046
git2_resource_handle = zend_register_list_destructors_ex(destruct_git2, NULL, PHP_GIT2_RESOURCE_NAME, module_number);
10241047

10251048
REGISTER_LONG_CONSTANT("GIT_TYPE_REPOSITORY", PHP_GIT2_TYPE_REPOSITORY, CONST_CS | CONST_PERSISTENT);

php_git2.h

+8
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,12 @@ typedef struct php_git2_odb_backend {
229229
php_git2_multi_cb_t *multi;
230230
} php_git2_odb_backend;
231231

232+
typedef struct php_git2_odb_backend_foreach_callback {
233+
zend_object zo;
234+
git_odb_foreach_cb callback;
235+
php_git2_cb_t *payload;
236+
} php_git2_odb_backend_foreach_callback;
237+
238+
extern zend_class_entry *php_git2_odb_backend_foreach_callback_class_entry;
239+
232240
#endif /* PHP_GIT2_H */

php_git2_priv.h

+29
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,35 @@ extern int git2_resource_handle;
3434
#define PHP_GIT2_LIST_INSERT(type, handle) zend_list_insert(type, handle)
3535
#endif
3636

37+
# if ZEND_MODULE_API_NO >= 20100525
38+
# define PHP_GIT2_STD_CREATE_OBJECT(STRUCT_NAME) \
39+
STRUCT_NAME *object;\
40+
\
41+
object = (STRUCT_NAME*)ecalloc(1, sizeof(*object));\
42+
zend_object_std_init(&object->zo, ce TSRMLS_CC);\
43+
object_properties_init(&object->zo, ce);\
44+
\
45+
retval.handle = zend_objects_store_put(object,\
46+
(zend_objects_store_dtor_t)zend_objects_destroy_object,\
47+
(zend_objects_free_object_storage_t) STRUCT_NAME##_free_storage ,\
48+
NULL TSRMLS_CC);\
49+
retval.handlers = zend_get_std_object_handlers();
50+
# else
51+
# define PHP_GIT2_STD_CREATE_OBJECT(STRUCT_NAME) \
52+
STRUCT_NAME *object;\
53+
zval *tmp = NULL;\
54+
\
55+
object = (STRUCT_NAME*)ecalloc(1, sizeof(*object));\
56+
zend_object_std_init(&object->zo, ce TSRMLS_CC);\
57+
zend_hash_copy(object->zo.properties, &ce->default_properties, (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *)); \
58+
\
59+
retval.handle = zend_objects_store_put(object,\
60+
(zend_objects_store_dtor_t)zend_objects_destroy_object,\
61+
(zend_objects_free_object_storage_t) STRUCT_NAME##_free_storage ,\
62+
NULL TSRMLS_CC);\
63+
retval.handlers = zend_get_std_object_handlers();
64+
# endif
65+
3766
#define PHP_GIT2_V(git2, type) git2->v.type
3867
#define GIT2_RVAL_P(git2) git2->resource_id
3968
#define GIT2_SHOULD_FREE(git2) git2->should_free_v

0 commit comments

Comments
 (0)