I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
Actually, this can be done. Through a php extension.
File: config.m4
PHP_ARG_ENABLE(test, whether to enable test Extension support, [ --enable-test Enable test ext support]) if test "$PHP_TEST" = "yes"; then AC_DEFINE(HAVE_TEST, 1, [Enable TEST Extension]) PHP_NEW_EXTENSION(test, test.c, $ext_shared) fi
File: php_test.h
#ifndef PHP_TEST_H #define PHP_TEST_H 1 #define PHP_TEST_EXT_VERSION "1.0" #define PHP_TEST_EXT_EXTNAME "test" PHP_FUNCTION(getaddress4); PHP_FUNCTION(getaddress); extern zend_module_entry test_module_entry; #define phpext_test_ptr &test_module_entry #endif
File: test.c
#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_test.h" ZEND_BEGIN_ARG_INFO_EX(func_args, 1, 0, 0) ZEND_END_ARG_INFO() static function_entry test_functions[] = { PHP_FE(getaddress4, func_args) PHP_FE(getaddress, func_args) {NULL, NULL, NULL} }; zend_module_entry test_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_TEST_EXT_EXTNAME, test_functions, NULL, NULL, NULL, NULL, NULL, #if ZEND_MODULE_API_NO >= 20010901 PHP_TEST_EXT_VERSION, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_TEST ZEND_GET_MODULE(test) #endif PHP_FUNCTION(getaddress4) { zval *var1; zval *var2; zval *var3; zval *var4; char r[500]; if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "aaaa", &var1, &var2, &var3, &var4) == FAILURE ) { RETURN_NULL(); } sprintf(r, "n%p - %p - %p - %pn%p - %p - %p - %p", var1, var2, var3, var4, Z_ARRVAL_P(var1), Z_ARRVAL_P(var2), Z_ARRVAL_P(var3), Z_ARRVAL_P(var4) ); RETURN_STRING(r, 1); } PHP_FUNCTION(getaddress) { zval *var; char r[100]; if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &var) == FAILURE ) { RETURN_NULL(); } sprintf(r, "%p", Z_ARRVAL_P(var)); RETURN_STRING(r, 1); }
Then all you have to do is phpize it, config it, and make it. Add a "extension=/path/to/so/file/modules/test.so" to your php.ini file. And finally, restart the web server, just in case.
<?php $x = array("123"=>"123"); $w = $x; $y = $x; $z = &$x; var_dump(getaddress4($w,$x,$y,$z)); var_dump(getaddress($w)); var_dump(getaddress($x)); var_dump(getaddress($y)); var_dump(getaddress($z)); ?>
Returns(at least for me, your memory addresses will probably be different)
string ' 0x9efeb0 - 0x9effe0 - 0x9ef8c0 - 0x9efeb0 0x9efee0 - 0x9f0010 - 0x9ed790 - 0x9efee0' (length=84) string '0x9efee0' (length=8) string '0x9f0010' (length=8) string '0x9ed790' (length=8) string '0x9efee0' (length=8)
Thanks to Artefacto for pointing this out, but my original code was passing the arrays by value, so thereby was recreating arrays including the referenced-one, and giving you bad memory values. I have since changed the code to force all params to be passed by reference. This will allow references, arrays, and object, to be passed in unmolested by the php engine. $w/$z are the same thing, but $w/$x/$y are not. The old code, actually showed the reference breakage and the fact that the memory addresses would change or match when all variables were passed in vs multiple calls to the same function. This was because PHP would reuse the same memory when doing multiple calls. Comparing the results of the original function would be useless. The new code should fix this problem.
FYI - I'm using php 5.3.2.
You can try below code to merge array. Code generates desired output required to you. I have used sample array as given by you:
<?php
$arr1=array(
"384"=>array("name"=>"SomeMovieName1","age"=>"12.2 hrs","IMDBLink"=>"","IMDBRating"=>"", "coverArt"=>""),
"452"=>array("name"=>"SomeMovieName2","age"=>"15.2 hrs","IMDBLink"=>"","IMDBRating"=>"", "coverArt"=>""),
"954"=>array("name"=>"SomeMovieName3","age"=>"4.2 hrs","IMDBLink"=>"","IMDBRating"=>"", "coverArt"=>"")
);
$arr2=array(
"384" => array("IMDBLink" => "7.2", "IMDBRating" => "http://www.imdb.com/LinkToMovie1", "coverArt" => "http://www.SomeLinkToCoverArt.com/1"),
"452" => array("IMDBLink" => "5","IMDBRating" => "http://www.imdb.com/LinkToMovie2", "coverArt" => "http://www.SomeLinkToCoverArt.com/2"),
"954"=>array("IMDBLink" => "8","IMDBRating" => "http://www.imdb.com/LinkToMovie3", "coverArt" => "http://www.SomeLinkToCoverArt.com/3")
);
$arr3 = array();
foreach($arr1 as $key=>$val)
{
$arr3[] = array_merge($val, $arr2[$key]);
}
echo "<pre>";
print_r($arr3);
?>
Using a simple regex via preg_match_all
and array_combine
is often the shortest and quickest option:
preg_match_all("/([^\\]+)\\([^\\]+)/", $string, $p);
$array = array_combine($p[1], $p[2]);
Now this is of course a special case. Both keys and values are separated by a backslash, as are all pairs of them. The regex is also a bit lengthier due to the necessary double escaping.
However this scheme can be generalized to other key:value,
-style strings.
key:value,
separatorsCommon variations include : and = as key/value separators, and , or & and others as pair delimiters. The regex becomes rather obvious in such cases (with the /x
flag for readability):
# ? ? ?
preg_match_all("/ ([^:]+) : ([^,]+) /x", $string, $p);
$array = array_combine($p[1], $p[2]);
Which makes it super easy to exchange :
and ,
for other delimiters.
=
instead of :
colons.\t
as pair delimiter (tab-separated key:value lists)&
or ;
as separator between key=value pairs.\s
spaces or \n
newlines even.You can make it more flexible/forgiving by allowing different delimiters between keys/values/pairs:
# ? ? ?
preg_match_all("/ ([^:=]+) [:=]+ ([^,+&]+) /x", $string, $p);
Where both key=value,key2:value2++key3==value3
would work. Which can make sense for more human-friendlinies (AKA non-technical users).
Oftentimes you may want to prohibit anything but classic key
identifiers. Just use a w+
word string pattern to make the regex skip over unwanted occurences:
# ? ? ?
preg_match_all("/ (w+) = ([^,]+) /x", $string, $p);
This is the most trivial whitelisting approach. If OTOH you want to assert/constrain the whole key/value string beforehand, then craft a separate preg_match("/^(w+=[^,]+(,|$))+/", …
You can skip a few post-processing steps (such as trim
on keys and values) with a small addition:
preg_match_all("/ s*([^=]+) s*=s* ([^,]+) (?<!s) /x", $string, $p);
Or for instance optional quotes:
preg_match_all("/ s*([^=]+) s*=s* '? ([^,]+) (?<![s']) /x", $string, $p);
And you can craft a baseline INI-file extraction method:
preg_match_all("/^ s*(w+) s*=s* ['"]?(.+?)['"]? s* $/xm", $string, $p);
Please note that this is just a crude subset of common INI schemes.
parse_str()
If you have a key=value&key2=value2
string already, then parse_str
works like a charm. But by combining it with strtr
can even process varying other delimiters:
# ?? ??
parse_str(strtr($string, ":,", "=&"), $pairs);
Which has a couple of pros and cons of its own:
%2F
for special characters).keys[]=
to arrays, which you may or may not want though.explode
+ foreach
You'll find many examples of manual key/value string expansion. Though this is often more code. explode
is somewhat overused in PHP due to optimization assumptions. After profiling often turns out to be slower however due to the manual foreach
and array collection.
The you can do this using compact
:
function myFunc($a, $b, $c) {
$params = compact('a', 'b', 'c');
// ...
}
Or, get_defined_vars()
will give you an associative array of all the variables defined in that scope, which would work, but I think this might also include $_POST
, $_GET
, etc...
Otherwise, you can use func_get_args
to get a list of all the arguments passed to the function. This is not associative though, since it is only data which is passed (that is, there's no variable names). This also lets you have any number of arguments in your function.
Or, just specify one argument, which is an array:
function myFunc($params) {
}
compact()
seems to be closest to what you're after though.
Just typecast it
From Arrays:
Example: Simple Object
Output:
Example: Complex Object
Output (with s edited in for clarity):
Output with
var_export
instead ofvar_dump
:Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.
Also see this in-depth blog post: