Strange foreach behaviour after an object casting - php

I get stuck with a strange PHP behaviour after a cast. Here is the code :
$obj = new stdClass();
$obj->{'0'} = "test";
$array = (array)$obj;
var_dump($array);
This code will output :
array(1) { ["0"]=> string(4) "test" }
Absolutely normal.
Now I add some code :
foreach ($array as $key => $value) {
$array[$key] = strtoupper($value);
}
var_dump($array);
This code outputs :
array(2) {
["0"]=>
string(4) "test"
[0]=>
string(4) "TEST"
}
Why my $key casted to int ?
If I try a simpler example :
$array = array("0" => "test");
foreach ($array as $key => $value) {
$array[$key] = strtoupper($value);
}
var_dump($array);
This will output :
array(1) { [0]=> string(4) "TEST" }
Does somebody know why there is a cast of my $key to int ?
Update
I tried to force to cast my key to string :
$array["{$key}"] = $value;
and
$array[(string)$key] = $value;
But they are inserted as int. So my question should be : is there a way to insert keys as string into an array?
I know that I can solve my problem by using a second array and dismiss strings :
$obj = new stdClass();
$obj->{'0'} = "test";
$array = (array)$obj;
$array2 = array();
foreach ($array as $key => $value) {
$array2[$key] = strtoupper($value);
}
But it would be nice to make it in a more beautiful way, conserving data type (and avoiding duplicating entries while iterating them as previously demonstrated).

From the PHP manual:
Strings containing valid integers will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.

#cHao found a clean and working solution to convert an object to an array without foreach() matters. My example becomes :
$array = array();
$obj = new stdClass();
$obj->{'0'} = "test";
foreach ($obj as $key => $value) {
$array[$key] = strtoupper($value);
}
stdClass is iterable.
Thank you!

Related

Set variable in foreach loop and pass by reference

I was playing with PHP recently and wanted to assign variable in foreach loop and pass value by reference at the same time. I was a little bit surprised that didn't work. Code:
$arr = array(
'one' => 'xxxxxxxx',
'two' => 'zzzzzzzz'
);
foreach ($foo = $arr as &$value) {
$value = 'test';
}
var_dump($foo);
Result:
array(2) { ["one"]=> string(8) "xxxxxxxx" ["two"]=> string(8) "zzzzzzzz" }
The following approach obviously does work:
$arr = array(
'one' => 'xxxxxxxx',
'two' => 'zzzzzzzz'
);
$foo = $arr;
foreach ($foo as &$value) {
$value = 'test';
}
var_dump($foo);
Result:
array(2) { ["one"]=> string(4) "test" ["two"]=> &string(4) "test" }
Does someone know why those snippets are not equivalent and what is being done behind the scenes?
$foo = $arr is trans by value, not reference, you should use $foo = &$arr. You can refer to Are arrays in PHP passed by value or by reference?
try this, live demo.
$arr = array(
'one' => 'xxxxxxxx',
'two' => 'zzzzzzzz'
);
foreach ($foo = &$arr as &$value) {
$value = 'test';
}
var_dump($foo);
foreach ($foo = $arr as &$value) {
$value = 'test';
}
first you assign the value of $arr[0] to $foo[0] then take that value and make that value = 'test' (this will not change $arr or $foo values "useless statement")
But here
$foo = $arr;
foreach ($foo as &$value) {
$value = 'test';
}
first you asign $arr to $foo
then go to for each statement , get the values of $foo and modify it
ex: $foo[0]='test' , $foo[1]='test' ...

Removing a JSON record from .json file with PHP

I have a json file looking like this :
[["{\"id\":1474721566304,\"name\":\"GGG\",\"brand\":\"GG\",\"price\":\"3\"}"],["{\"id\":1474721570904,\"name\":\"GGGH\",\"brand\":\"GGH\",\"price\":\"4\"}"],["{\"id\":1474721574188,\"name\":\"GGGH\",\"brand\":\"GGHH\",\"price\":\"5\"}"]]
What I am trying to do is to remove a record from it by it's id. For this purpose I have the following PHP code :
<?php
$string = file_get_contents("products.json");
$json_a = json_decode($string, true); //turning JSON-string into an array containing JSON-strings
$arr = array();
foreach ($json_a as $key) {
array_push($arr,json_decode($key[0],true)); //and here you turning each of the JSON-strings into objects themselves
}
$data= $_GET['data'];
$i=0;
foreach($arr as $element) {
if($data == $element["id"]){
unset($arr[$i]);//removing the product by ID
}
$i++;
}
var_dump($arr);
$arr2 = array();
foreach ($arr as $key) {//trying to make it look like the original json.
array_push($arr2,json_decode($key[0],true));
}
//var_dump($arr2);
echo json_encode($arr2);
?>
What I am getting from this code is :
array(2) { [0]=> array(4) { ["id"]=> float(1474721566304) ["name"]=> string(3) "GGG" ["brand"]=> string(2) "GG" ["price"]=> string(1) "3" } [1]=> array(4) { ["id"]=> float(1474721570904) ["name"]=> string(4) "GGGH" ["brand"]=> string(3) "GGH" ["price"]=> string(1) "4" } }
I am really out of ideas how to make this array look like my original JSON shown first on this post. I tried many different things, but I couldn't make it work. My idea is after removing the record by it's ID to replace the old JSON with the new one that I am trying to construct here.
I am new to php and I'd appreciate any input on my issue.
First of all - your input JSON is wrong:
array (size=3)
0 =>
array (size=1)
0 => string '{"id":1474721566304,"name":"GGG","brand":"GG","price":"3"}' (length=58)
1 =>
array (size=1)
0 => string '{"id":1474721570904,"name":"GGGH","brand":"GGH","price":"4"}' (length=60)
2 =>
array (size=1)
0 => string '{"id":1474721574188,"name":"GGGH","brand":"GGHH","price":"5"}' (length=61)
You don't have 'id' nor 'name', 'GGG' and other keys. You just have one long string. You should remove unnecessary quotation marks. After that your JSON should look like this:
[[{"id":1474721566304,"name":"GGG","brand":"GG","price":"3"}],[{"id":1474721570904,"name":"GGGH","brand":"GGH","price":"4"}],[{"id":1474721574188,"name":"GGGH","brand":"GGHH","price":"5"}]]
And finally, your PHP code can be much shorter:
$json = "[[{\"id\":1474721566304,\"name\":\"GGG\",\"brand\":\"GG\",\"price\":\"3\"}],[{\"id\":1474721570904,\"name\":\"GGGH\",\"brand\":\"GGH\",\"price\":\"4\"}],[{\"id\":1474721574188,\"name\":\"GGGH\",\"brand\":\"GGHH\",\"price\":\"5\"}]]";
$input = json_decode($json, true);
$output = array();
foreach($input as $element) { //you don't need to declare yet another array, just use the one you already have
if($_GET['data'] != $element[0]["id"]){ //and not unset, just add to new array if you want
$output[] = $element; //shorter and faster than array_push()
}
}
echo json_encode($output);
Try this code:
$string = file_get_contents("product.json");
$json_a = json_decode($string, true); //turning JSON-string into an array containing JSON-strings
$arr = array();
foreach ($json_a as $key) {
array_push($arr,json_decode($key[0],true)); //and here you turning each of the JSON-strings into objects themselves
}
$data= 0;
$i=0;
foreach($arr as $element) {
if($data == $element["id"]){
unset($arr[$i]);//removing the product by ID
}
$i++;
}
// print_r($arr);
$arr2 = array();
foreach($arr as $key => $val) {
$arr2[][] = $val;
}
//var_dump($arr2);
echo json_encode($arr2);

How to delete elements from array from certain value on?

I have an array in PHP and I don't know how to delete all the elements from every array element from certain character on, icluding that character. Is there a way to do this?
array(1092) {
["Piper;Rosii;Sare;Test;Vinete#####Piper ->Negru;Rosii ->Călite;Sare ->De masă, grunjoasă;Vinete ->Prăjite"]=>
int(124)
}
In my example I want to delete all text from "#####", including "#####" to the end, foreach array element. Is this possible? Or is there a PHP function for this?
UPDATE
My result should look like this:
array(1092) {
["Piper;Rosii;Sare;Test;Vinete]=>
int(124)
}
You can use array_walk to apply the substr and strpos to each element:
$array = [
'23845637;54634;345;3453345;#####morestuff',
'234234#####34596078345j34534534',
'34343245dfg#####asdfsadf;23452345;sdfsdf;345345'
];
array_walk($array, function(&$value, $key) {
$value = substr($value, 0, strpos($value, '#####'));
});
var_dump($array);
Will result in:
array(3) {
[0]=>
string(27) "23845637;54634;345;3453345;"
[1]=>
string(6) "234234"
[2]=>
string(11) "34343245dfg"
}
This will modify the original array.
For each element in the array, we search for the position of '#####' in the string and only take the part from 0 to the position in the string where '#####' occurs.
This will do that by looping through the array exploding the key by ##### and adding it to a new array. I did it in a loop in case your array is bigger than 1
<?php
$oldArray = array("Piper;Rosii;Sare;Test;Vinete#####Piper ->Negru;Rosii ->Călite;Sare ->De masă, grunjoasă;Vinete ->Prăjite" => 124);
$newArray = array();
foreach ($oldArray as $key => $row) {
$newKey = explode('#####', $key);
$newArray[$newKey[0]] = $row;
}
var_dump($newArray);
You can use substr and strpos to add the new entry and then unset the old entry in the array like this example:
$array = array(
"Piper;Rosii;Sare;Test;Vinete#####Piper ->Negru;Rosii ->Călite;Sare ->De masă, grunjoasă;Vinete ->Prăjite" => 124
);
foreach ($array as $key => $value) {
$array[substr($key, 0, strpos($key, '#####'))] = $value;
unset($array[$key]);
}
var_dump($array);
Will result in:
array(1) {
["Piper;Rosii;Sare;Test;Vinete"]=>
int(124)
}

Changes to array of JSON objects based on other array

I have an array of JSON objects that look like this:
{"id":1,"place":2,"pic_name":"aaa.jpg"}
My PHP file receives a simple array like:
["4","3","1","2","5"]
These numbers correspond to the place value in my JSON object. Now I need to compare the place of each element in the secont array with the value of ID in the JSON object and if the match I have to replace the value of PLACE with the element from the array.
I am having problems doing the comparison. Any guidelines? What I come up with:
foreach($ids as $index=>$id) { //the array
$id = (int) $id;
foreach ($obj as $key=>$value) { //the JSON objects
foreach ($value as $k=>$v){
if ($id != '' && array_search($index, array_keys($ids)) == $value[$k]['id']) {
$value[$k]['place'] = $id;
file_put_contents($file, json_encode($ids));
} else { print "nope";}
} } }
That will be:
$array = [
'{"id":1,"place":2,"pic_name":"aaa.jpg"}',
'{"id":2,"place":5,"pic_name":"aab.jpg"}',
'{"id":3,"place":1,"pic_name":"aba.jpg"}',
'{"id":4,"place":3,"pic_name":"baa.jpg"}',
'{"id":5,"place":4,"pic_name":"abb.jpg"}'
];
$places = ["4","3","1","2","5"];
$array = array_map(function($item)
{
return json_decode($item, 1);
}, $array);
foreach($array as $i=>$jsonData)
{
if(false!==($place=array_search($jsonData['id'], $places)))
{
$array[$i]['place'] = $place+1;
}
}
$array = array_map('json_encode', $array);
//var_dump($array);
-with output like:
array(5) {
[0]=>
string(39) "{"id":1,"place":3,"pic_name":"aaa.jpg"}"
[1]=>
string(39) "{"id":2,"place":4,"pic_name":"aab.jpg"}"
[2]=>
string(39) "{"id":3,"place":2,"pic_name":"aba.jpg"}"
[3]=>
string(39) "{"id":4,"place":1,"pic_name":"baa.jpg"}"
[4]=>
string(39) "{"id":5,"place":5,"pic_name":"abb.jpg"}"
}

Access array by string key x, where x is "123"

We have an array of which the keys are Strings, but those strings sometimes just are numbers (e.g. "123"). When trying to access the array by the key "123", we get an Undefined Index notice. When accessing it by just the integer 123, we get the Undefined Offset notice. This tells us we're trying to index it correctly using the "123" string, but it's still not set.
Trying to come up with an example for this SO question this is hard, since PHP converts array keys in our test case to integers automatically, while in our real-world application this does not happen (due to use of a Java Bridge). The test array we're trying now is:
<?php
$array = array("123" => array(108, 8));
var_dump($array);
?>
This returns:
array(1) { [123]=> array(2) { [0]=> int(108) [1]=> int(8) } }
While in our real-world equivalent, it would return:
array(1) { ["123"]=> array(2) { [0]=> int(108) [1]=> int(8) } }
So in the real world the index actually is a String:
<?php
var_dump(array_keys($array));
?>
returns
array(1) { [0]=> string(3) "123" }
So, finally the question is the output of the following code:
<?php
foreach ($array as $key => $value) {
if (!isset($array[$key])) {
print "What is happening here?";
}
}
?>
which gives:
What is happening here?
Based on Yoshi's comment, here's working test code:
<?php
$array = (array)json_decode('{"123":[108,8]}');
foreach ($array as $key => $value) {
if (!isset($array[$key])) {
print "What is happening here?";
} else {
print "Nothing to see here, move along";
}
}
?>
Not very elegant solution too, but also works and do not require recreating array. Also, you can access the element value.
$array = (array)json_decode('{"123":100}');
$array_keys = array_keys($array);
$array = (object)$array;
foreach ($array_keys as $key)
{
if (!isset($array->$key))
{
print "What is happening here?";
}
else {
print "It's OK val is {$array->$key}";
}
}
Note $ before key in $array->$key, it is important.
Look at this code (and line $array[(string)$key])
<?php
$array = array("123" => array(108, 8));
foreach ($array as $key => $value)
{
if (!isset($array[(string)$key]))
{
print "What is happening here?";
}
else print "It's just types";
}
Type of $key was automatically casted to integer, and it's why this key was not found in array.
All information about it you can find in manual: http://php.net/manual/en/language.types.type-juggling.php
This code will works with both cases:
foreach ($array as $key => $value)
{
if (!array_key_exists($key, $array))
{
print "What is happening here?";
}
else print "It's just types";
}
I had the same problem (but with array_intersect_key).
Here is my solution:
$array = array_combine(array_keys($array), $array)

Categories