How does PHP array_keys do the search for value?
Example:
$array2 = array("xyz", "xyz", "abc", "abc", "xyz", "xyz", "text", "abc", "text");
print_r(array_keys($array2,"abc"));
Since they are key,value pairs. I am guessing PHP to do a search based on hash rather than iterate through each of the key-pairs in the array.
Any 'clarity thoughts' on this?
Question inspired by this question: How to get the keys of empty elements in an array if the corresponding element in a similar-sized array is a number (without iteration)?
In the php source, they iterate through each key and value, one by one.
https://github.com/php/php-src/blob/master/ext/standard/array.c#L2439
/* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])
Return just the keys from the input array, optionally only for the specified search_value */
PHP_FUNCTION(array_keys)
{
zval *input, /* Input array */
*search_value = NULL, /* Value to search for */
**entry, /* An entry in the input array */
res, /* Result of comparison */
*new_val; /* New value */
int add_key; /* Flag to indicate whether a key should be added */
char *string_key; /* String key */
uint string_key_len;
ulong num_key; /* Numeric key */
zend_bool strict = 0; /* do strict comparison */
HashPosition pos;
int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {
return;
}
if (strict) {
is_equal_func = is_identical_function;
}
/* Initialize return array */
if (search_value != NULL) {
array_init(return_value);
} else {
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
}
add_key = 1;
/* Go through input array and add keys to the return array */
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
if (search_value != NULL) {
is_equal_func(&res, search_value, *entry TSRMLS_CC);
add_key = zval_is_true(&res);
}
if (add_key) {
MAKE_STD_ZVAL(new_val);
switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 1, &pos)) {
case HASH_KEY_IS_STRING:
ZVAL_STRINGL(new_val, string_key, string_key_len - 1, 0);
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
break;
case HASH_KEY_IS_LONG:
Z_TYPE_P(new_val) = IS_LONG;
Z_LVAL_P(new_val) = num_key;
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
break;
}
}
zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
}
}
/* }}} */
Please see the array_keys definition, take note also for the comments which explain it pretty well:
Return just the keys from the input array, optionally only for the specified search_value
and later on:
Go through input array and add keys to the return array
The definition as follows for PHP 5.3 on ext/standard/array.c:
2427 /* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])
2428 Return just the keys from the input array, optionally only for the specified search_value */
2429 PHP_FUNCTION(array_keys)
2430 {
2431 zval *input, /* Input array */
2432 *search_value = NULL, /* Value to search for */
2433 **entry, /* An entry in the input array */
2434 res, /* Result of comparison */
2435 *new_val; /* New value */
2436 int add_key; /* Flag to indicate whether a key should be added */
2437 char *string_key; /* String key */
2438 uint string_key_len;
2439 ulong num_key; /* Numeric key */
2440 zend_bool strict = 0; /* do strict comparison */
2441 HashPosition pos;
2442 int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
2443
2444 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {
2445 return;
2446 }
2447
2448 if (strict) {
2449 is_equal_func = is_identical_function;
2450 }
2451
2452 /* Initialize return array */
2453 if (search_value != NULL) {
2454 array_init(return_value);
2455 } else {
2456 array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
2457 }
2458 add_key = 1;
2459
2460 /* Go through input array and add keys to the return array */
2461 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
2462 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
2463 if (search_value != NULL) {
2464 is_equal_func(&res, search_value, *entry TSRMLS_CC);
2465 add_key = zval_is_true(&res);
2466 }
2467
2468 if (add_key) {
2469 MAKE_STD_ZVAL(new_val);
2470
2471 switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 1, &pos)) {
2472 case HASH_KEY_IS_STRING:
2473 ZVAL_STRINGL(new_val, string_key, string_key_len - 1, 0);
2474 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
2475 break;
2476
2477 case HASH_KEY_IS_LONG:
2478 Z_TYPE_P(new_val) = IS_LONG;
2479 Z_LVAL_P(new_val) = num_key;
2480 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
2481 break;
2482 }
2483 }
2484
2485 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
2486 }
2487 }
2488 /* }}} */
The search that is performed is also explained on the PHP manual page for array_keysDocs:
If the optional search_value is specified, then only the keys for that value are returned. Otherwise, all the keys from the input are returned.
See also the $strict parameter to influence how values are compared:
Determines if strict comparison (===) should be used during the search.
The two types of comparison == (Equal) and === (Identical) are documented as well.
I suspect this to be not so easy:
If you do NOT give the last parameter "strict" as true, PHP might
need to walk the array, along the way converting values to a
compareable type.
If you DO give "strict" as true, it might also be necessary to iterate the array to exclude wrong types
Related
When recursively iterating using an instance of \RecursiveIteratorIterator is it expected behaviour that in looking for a sub iterator of a depth greater than your current depth, it always returns null?
Please see: RecursiveIteratorIterator::getSubIterator
public RecursiveIterator RecursiveIteratorIterator::getSubIterator ([
int $level ] )
Example:
$innerIterator = new \RecursiveArrayIterator([/*a recursive array*/]);
$iterator = new \RecursiveIteratorIterator($innerIterator);
foreach ($iterator as $value) {
$depth = $iterator->getDepth();
$parentDepth = $depth - 1;
$childDepth = $depth + 1;
// returns \RecursiveArrayIterator
$iterator->getSubIterator($depth);
// returns null first iteration and \RecursiveArrayIterator thereafter
$iterator->getSubIterator($parentDepth);
// always returns null...should it?
$iterator->getSubIterator($childDepth);
}
The RecursiveIteratorIterator::getSubIterator() method's source code is short enough to be posted here, and is as good a place as any to find an answer.
/* {{{ proto RecursiveIterator RecursiveIteratorIterator::getSubIterator([int level])
The current active sub iterator or the iterator at specified level */
SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
{
spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
long level = object->level;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) {
return;
}
if (level < 0 || level > object->level) {
RETURN_NULL();
}
RETURN_ZVAL(object->iterators[level].zobject, 1, 0);
} /* }}} */
— From the PHP 5.5.14 source.
The key part for this question is the if statement:
if (level < 0 || level > object->level) {
RETURN_NULL();
}
The code is pretty self-explanatory, but it is saying:
If the specified level is less than zero, or greater than the current object's level, return null.
are these functions written the same way as user functions? I mean with PHP code and with regular expressions and stuff like that?
For example:
filter_var($email, FILTER_VALIDATE_EMAIL);
vs.
http://www.totallyphp.co.uk/code/validate_an_email_address_using_regular_expressions.htm
PHP is written in C. The PHP functions are written in high quality C code then compiled to form the PHP langugae library
if you want to extend PHP (edit / write) own functions check this out: http://www.php.net/~wez/extending-php.pdf
EDIT:
here you go :
This is the original C code for the function:
/* {{{ proto mixed filter_var(mixed variable [, long filter [, mixed options]])
* Returns the filtered version of the vriable.
*/
PHP_FUNCTION(filter_var)
{
long filter = FILTER_DEFAULT;
zval **filter_args = NULL, *data;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|lZ", &data, &filter, &filter_args) == FAILURE) {
return;
}
if (!PHP_FILTER_ID_EXISTS(filter)) {
RETURN_FALSE;
}
MAKE_COPY_ZVAL(&data, return_value);
php_filter_call(&return_value, filter, filter_args, 1, FILTER_REQUIRE_SCALAR TSRMLS_CC);
}
/* }}} */
static void php_filter_call(zval **filtered, long filter, zval **filter_args, const int copy, long filter_flags TSRMLS_DC) /* {{{ */
{
zval *options = NULL;
zval **option;
char *charset = NULL;
if (filter_args && Z_TYPE_PP(filter_args) != IS_ARRAY) {
long lval;
PHP_FILTER_GET_LONG_OPT(filter_args, lval);
if (filter != -1) { /* handler for array apply */
/* filter_args is the filter_flags */
filter_flags = lval;
if (!(filter_flags & FILTER_REQUIRE_ARRAY || filter_flags & FILTER_FORCE_ARRAY)) {
filter_flags |= FILTER_REQUIRE_SCALAR;
}
} else {
filter = lval;
}
} else if (filter_args) {
if (zend_hash_find(HASH_OF(*filter_args), "filter", sizeof("filter"), (void **)&option) == SUCCESS) {
PHP_FILTER_GET_LONG_OPT(option, filter);
}
if (zend_hash_find(HASH_OF(*filter_args), "flags", sizeof("flags"), (void **)&option) == SUCCESS) {
PHP_FILTER_GET_LONG_OPT(option, filter_flags);
if (!(filter_flags & FILTER_REQUIRE_ARRAY || filter_flags & FILTER_FORCE_ARRAY)) {
filter_flags |= FILTER_REQUIRE_SCALAR;
}
}
if (zend_hash_find(HASH_OF(*filter_args), "options", sizeof("options"), (void **)&option) == SUCCESS) {
if (filter != FILTER_CALLBACK) {
if (Z_TYPE_PP(option) == IS_ARRAY) {
options = *option;
}
} else {
options = *option;
filter_flags = 0;
}
}
}
if (Z_TYPE_PP(filtered) == IS_ARRAY) {
if (filter_flags & FILTER_REQUIRE_SCALAR) {
if (copy) {
SEPARATE_ZVAL(filtered);
}
zval_dtor(*filtered);
if (filter_flags & FILTER_NULL_ON_FAILURE) {
ZVAL_NULL(*filtered);
} else {
ZVAL_FALSE(*filtered);
}
return;
}
php_zval_filter_recursive(filtered, filter, filter_flags, options, charset, copy TSRMLS_CC);
return;
}
if (filter_flags & FILTER_REQUIRE_ARRAY) {
if (copy) {
SEPARATE_ZVAL(filtered);
}
zval_dtor(*filtered);
if (filter_flags & FILTER_NULL_ON_FAILURE) {
ZVAL_NULL(*filtered);
} else {
ZVAL_FALSE(*filtered);
}
return;
}
php_zval_filter(filtered, filter, filter_flags, options, charset, copy TSRMLS_CC);
if (filter_flags & FILTER_FORCE_ARRAY) {
zval *tmp;
ALLOC_ZVAL(tmp);
MAKE_COPY_ZVAL(filtered, tmp);
zval_dtor(*filtered);
array_init(*filtered);
add_next_index_zval(*filtered, tmp);
}
}
AND HERE IS YOUR VALIDATE EMAIL ROUTINE:
-- this answers your question. Yes, it is done by regex internally.
void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
/*
* The regex below is based on a regex by Michael Rushton.
* However, it is not identical. I changed it to only consider routeable
* addresses as valid. Michael's regex considers a#b a valid address
* which conflicts with section 2.3.5 of RFC 5321 which states that:
*
* Only resolvable, fully-qualified domain names (FQDNs) are permitted
* when domain names are used in SMTP. In other words, names that can
* be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed
* in Section 5) are permitted, as are CNAME RRs whose targets can be
* resolved, in turn, to MX or address RRs. Local nicknames or
* unqualified names MUST NOT be used.
*
* This regex does not handle comments and folding whitespace. While
* this is technically valid in an email address, these parts aren't
* actually part of the address itself.
*
* Michael's regex carries this copyright:
*
* Copyright © Michael Rushton 2009-10
* http://squiloople.com/
* Feel free to use and redistribute this code. But please keep this copyright notice.
*
*/
const char regexp[] = "/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}#)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*#(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD";
pcre *re = NULL;
pcre_extra *pcre_extra = NULL;
int preg_options = 0;
int ovector[150]; /* Needs to be a multiple of 3 */
int matches;
/* The maximum length of an e-mail address is 320 octets, per RFC 2821. */
if (Z_STRLEN_P(value) > 320) {
RETURN_VALIDATION_FAILED
}
re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC);
if (!re) {
RETURN_VALIDATION_FAILED
}
matches = pcre_exec(re, NULL, Z_STRVAL_P(value), Z_STRLEN_P(value), 0, 0, ovector, 3);
/* 0 means that the vector is too small to hold all the captured substring offsets */
if (matches < 0) {
RETURN_VALIDATION_FAILED
}
}
/* }}} */
PHP functions are either :
Written in C -- and not in PHP
Or just wrappers to functions provided by other libraries (For instance, PHP's curl extension is just a wrapper arround the curl library).
If you are curious, you can take a look at the sources of PHP -- here's its SVN : http://svn.php.net/viewvc/
For instance, the filter_var() function should be defined somewhere in the sources of the filter extension.
Nope. PHP-internal functions are written in C, not with PHP code. Which looks quite unwieldy due to the many Zend-runtime macros and how parameters are transferred from PHP into C structures.
That particular function does use a regular expression. It also makes a nice example:
http://svn.php.net/repository/php/php-src/branches/PHP_5_3/ext/filter/logical_filters.c
Look for regexp[] somewhere in the middle.
I'm using SWIG to generate a PHP extension over GLib which uses callbacks. To allow using PHP user-space functions as callbacks, i'm using something like:
The Wrapper (registers a unique callback dispatcher to handle all signal emissions):
/* {{{ proto void my_signal_connect(resource $instance, string $signal, mixed $callback, mixed $additional_args) }}}*/
ZEND_NAMED_FUNCTION(_wrap_my_signal_connect) {
GstObject *instance = (GstObject *) 0 ;
gchar *signal = (gchar *) 0 ;
zval *zcallback = (zval *) 0 ;
zval *zargs = (zval *) 0 ;
zval **args[4];
gulong result;
struct the_callback_struct *cb;
GType itype;
guint signal_id;
GSignalQuery *signal_info;
char *callback_name;
/* parse arguments */
SWIG_ResetError();
if(ZEND_NUM_ARGS() != 4 || zend_get_parameters_array_ex(4, args) != SUCCESS) {
WRONG_PARAM_COUNT;
}
{
if(SWIG_ConvertPtr(*args[0], (void **) &instance, 0, 0) < 0) {
if((*args[0])->type==IS_NULL) instance = 0;
else SWIG_PHP_Error(E_ERROR, "Wrapper: Type error in argument 1. Expected SWIGTYPE_p_p_void");
}
}
if((*args[1])->type == IS_NULL) {
signal = (gchar *) 0;
} else {
convert_to_string_ex(args[1]);
signal = (gchar *) Z_STRVAL_PP(args[1]);
}
MAKE_STD_ZVAL(zcallback);
*zcallback = **args[2];
zval_copy_ctor(zcallback);
MAKE_STD_ZVAL(zargs);
*zargs = **args[3];
zval_copy_ctor(zargs);
/* query the signal system for in-depth info about the signal */
{
itype = G_TYPE_FROM_INSTANCE((GObject *) instance);
signal_id = g_signal_lookup((const gchar *) signal, itype);
if(signal_id == 0) {
SWIG_PHP_Error(E_ERROR, "The object does not emit the given signal");
}
signal_info = (GSignalQuery *) emalloc(sizeof(*signal_info));
g_signal_query(signal_id, signal_info);
}
/* get the function name or object + method name */
cb = (struct callback_struct *)emalloc(sizeof(*cb));
if(zcallback->type == IS_NULL) {
SWIG_PHP_Error(E_ERROR, "Wrapper: Type error in callback argument.");
}
if(zcallback->type == IS_ARRAY) {
HashTable *ht = Z_ARRVAL_P(zcallback);
int n = zend_hash_num_elements(ht);
if(n == 2) {
if(zend_hash_index_find(ht, 0, (void **)&cb->target) == SUCCESS && Z_TYPE_PP(cb->target) == IS_OBJECT) {
if(zend_hash_index_find(ht, 1, (void **)&tmp2) == SUCCESS && Z_TYPE_PP(tmp2) == IS_STRING) {
MAKE_STD_ZVAL(cb->fx);
*cb->fx = **tmp2;
zval_copy_ctor(cb->fx);
}
}
}
} else if(zcallback->type == IS_STRING) {
cb->target = NULL;
MAKE_STD_ZVAL(cb->fx);
*cb->fx = *zcallback;
zval_copy_ctor(cb->fx);
} else {
SWIG_PHP_Error(E_ERROR, "Wrapper: Type error in callback argument.");
}
/* Validate callback */
if(zend_is_callable(cb->fx, 0, &callback_name) == FAILURE) {
efree(callback_name);
SWIG_PHP_Error(E_ERROR, "Invalid callback");
}
/* copy the args into the structure */
MAKE_STD_ZVAL(cb->args);
*cb->args = *zargs;
zval_copy_ctor(cb->args);
cb->signal_id = signal_info->signal_id;
cb->signal_name = signal_info->signal_name;
cb->signal_flags = signal_info->signal_flags;
cb->itype = signal_info->itype;
cb->return_type = signal_info->return_type;
cb->n_params = signal_info->n_params;
cb->param_types = signal_info->param_types;
/* connect the signal handler */
result = (gulong)g_signal_connect(instance, signal, G_CALLBACK(my_signal_dispatcher), (gpointer) cb);
{
ZVAL_LONG(return_value,result);
}
return;
fail:
zend_error(SWIG_ErrorCode(),"%s",SWIG_ErrorMsg());
}
The callback struct:
struct callback_struct {
zval **target;
zval *fx;
zval *args;
GType itype; /* The type of object/instance which emitted the signal */
guint signal_id; /* The signal id (or 0 if the signal is unknown) */
const gchar *signal_name; /* The signal name */
GSignalFlags signal_flags; /* The signal flags (as declared when creating the signal) */
GType return_type; /* The return type for the callback */
guint n_params; /* The number of parameters of the callback */
const GType *param_types; /* The parameter types for callback arguments */
};
The signal dispatcher maps the signal handling to a PHP user space function:
static void my_signal_dispatcher(gpointer instance, ...) {
int i = 0, addr;
gpointer arg, ref;
zval retval;
zval *arglist[3];
struct callback_struct *cb;
/* add emitter instance to arg list */
SWIG_SetPointerZval(arglist[i++], (void *) instance, SWIGTYPE_p__GObject, 1);
va_list ap;
va_start(ap, instance);
/* fetch the variable list of arguments */
while((addr = va_arg(ap, int)) > 2) {
arg = (gpointer) addr;
if(G_IS_OBJECT(arg)) {
SWIG_SetPointerZval(arglist[i++], (void *) arg, SWIGTYPE_p__GObject, 1);
} else {
cb = (struct callback_struct *) arg;
MAKE_STD_ZVAL(arglist[i]);
*arglist[i] = *cb->args;
zval_copy_ctor(arglist[i]);
i++;
break;
}
}
va_end(ap);
if(cb->target == NULL) {
if(call_user_function(EG(function_table), NULL, cb->fx, &retval, i, arglist TSRMLS_CC) == SUCCESS) {
zval_dtor(&retval);
}
} else {
if(call_user_function(NULL, cb->target, cb->fx, &retval, i, arglist TSRMLS_CC) == SUCCESS) {
zval_dtor(&retval);
}
}
zval_ptr_dtor(cb->target);
zval_dtor(cb->fx);
zval_dtor(cb->args);
efree(cb);
}
I'am able to build the extension, and to connect a PHP signal handler (callback) to a given signal, for example:
<?php
//...
function cb() {
$s = array();
foreach(func_get_args() as $arg) {
$s[] = gettype($arg) == 'resource' ? 'Resource '.get_resource_type($arg) : (gettype($arg) == 'object' ? 'Object '.get_class($arg) : gettype($arg));
}
$s = implode(', ', $s);
echo " { PHP user-space: cb($s) } ";
return 1;
}
//...
myextension::my_signal_connect($instance, "child-added", array('one' => 1));
?>
so, when $instance emits the "child-added" signal i got the output from the cb() PHP function, and the following error:
{ PHP user-space: cb(Resource _p__GObject, Resource _p__GObject, array) }
*** glibc detected *** php: free(): invalid pointer: 0x095080c8 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(+0x6b591)[0xb95591]
/lib/tls/i686/cmov/libc.so.6(+0x6cde8)[0xb96de8]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0xb99ecd]
/usr/lib/php5/20090626+lfs/myextension.so(+0x2a477)[0x7510477]
php[0x831c024]
php(zend_hash_del_key_or_index+0x112)[0x831af82]
php(_zend_list_delete+0x8c)[0x831c2ec]
php(_zval_dtor_func+0xb2)[0x830b872]
php(_zval_ptr_dtor+0x4d)[0x82ff00d]
php[0x82ff0c9]
php(zend_call_function+0x764)[0x8301694]
php(call_user_function_ex+0x64)[0x83023b4]
php(call_user_function+0x6b)[0x830242b]
/usr/lib/php5/20090626+lfs/gstreamer.so(+0x93c2d)[0x7579c2d]
/usr/lib/libgobject-2.0.so.0(g_cclosure_marshal_VOID__OBJECT+0x88)[0xd262d8]
======= Memory map: ========
00110000-0026e000 r-xp 00000000 08:04 440863 /usr/lib/libdb-4.8.so
0026e000-00270000 r--p 0015d000 08:04 440863 /usr/lib/libdb-4.8.so
00270000-00271000 rw-p 0015f000 08:04 440863 /usr/lib/libdb-4.8.so
...
I've tried to ref the GObject instances using g_object_ref() when connecting the signal before adding to the arguments list, without success
Any help?
I want to convert Zval to char*. how do i do that in my php extension?
It the zval represents a string, you can use Z_STRVAL (or Z_STRVAL_P/Z_STRVAL_PP if you have a zval*/zval**).
Otherwise, you may have to convert the zval before :
zval *var;
char *cstr;
int cstrlen;
/* ... */
if (Z_TYPE_P(var) != IS_STRING) {
convert_to_string(var);
}
cstr = Z_STRVAL_P(var);
cstrlen = Z_STRLEN_P(var);
If you don't want to change the original zval and you want to change the resulting C string, you can do:
zval *var, *varcopy;
char *cstr;
int cstrlen;
if (Z_TYPE_P(var) != IS_STRING) {
ALLOC_INIT_ZVAL(varcopy);
*varcopy = *var;
INIT_PZVAL(varcopy); /* reset refcount and clear is_ref */
zval_copy_ctor(varcopy);
convert_to_string(varcopy);
} else {
varcopy = var;
}
cstrlen = Z_STRLEN_P(varcopy);
cstr = estrndup(Z_STRVAL_P(varcopy), cstrlen);
if (varcopy != var) {
zval_ptr_dtor(&varcopy);
}
Writing a PHP extension in C, I want to convert a userland object (IS_OBJECT) to a string through __toString() if it has one, and fail otherwise. What should I use?
I don't need another zval on output, just a char *.
zval *zo;
switch (Z_TYPE_P(zo)) {
case IS_STRING:
... Z_STRVAL_P(zo) ...
break;
case IS_OBJECT:
... ???(zo) ...
break;
...
}
The reflection module does something like
ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring") - 1, 1);
result= call_user_function_ex(NULL, &object, &fname, &retval_ptr, 0, NULL, 0, NULL TSRMLS_CC);
zval_dtor(&fname);
if (result == FAILURE) {
_DO_THROW("Invocation of method __toString() failed");
/* Returns from this function */
}
And then you'd extract the char* with Z_STRVAL_P().
But I guess you could also use
case IS_OBJECT:
if ( SUCCESS==zend_std_cast_object_tostring(uservar, uservar, IS_STRING TSRMLS_CC) ) {
int len = Z_STRLEN_P(uservar);
char* pValue = Z_STRVAL_P(uservar);
...
}
zend_std_cast_object_tostring() is implemented in zend/zend_object_handlers.c. You might want to check if it really does what you want