I'm a newbie in the PHP area, so please bear with my question.
Basically I have/will have a pretty big json file, and I need to query the file to get a single entry based on the key provided. An example would be as follow:
{
"key1" : {value1},
"key2" : {value2},
...,
"keyn" : {valuen}
}
I will need to retrieve only one value at any one request, and hope to get a better performance.
The basic way to deal with this sort of handling in PHP from my search is to use json_decode() and then foreach.
However, this approach seems like need to iterate through the whole file based on the order of the key and what the key I am looking for. So if I am looking for keyn, then essentially I have to read from top to bottom of the large file. (Yep, I can use some sort algorithm to get a better result)
But from my understanding, JSON is basically another form of HashMap, so given HashMap can get easily and fast, is there a similar way in PhP to get the best performance out of it?
Well, given the structure you provided you definitely don't need to loop through the entire object.
If you're looking for keyn, you would just do:
$obj = json_decode($input);
echo $obj->keyn;
Maybe I'm missing something obvious. If you want to prevent having to json_decode the entire object, your question makes a bit more sense though... but that's not what you're asking.
From JSON.org
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, >record, struct, dictionary, hash table, keyed list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or >sequence.
You can't just interact with json without first using json_decode() to turn it into a usable object. But if you know the keys, after running json_decode() you can interact with it (because it's now an object). for example:
<?php
$string = '{"foo": "bar", "cool": "attr"}';
$result = json_decode($string);
// Result: object(stdClass)#1 (2) { ["foo"]=> string(3) "bar" ["cool"]=> string(4) "attr" }
var_dump($result);
// Prints "bar"
echo $result->foo;
// Prints "attr"
echo $result->cool;
?>
In situations like this, var_dump() and print_r() are your friends.
There really isn't any magical way to find the value without using any kind of loop
I haven't benchmarked this:
This is how I would approach the problem without having to finish the iterating over the whole tree if and when a match is foudn
$key = 'keyn'
$obj = json_decode(file_get_contents('path/to/your/file'), true);
$len = count($obj);
$match = false;
for($ii = 0; $ii < $len; $ii++){
$curr = $obj[$ii];
if($curr == $key) {
$match = $curr;
}
break;
}
In PHP you can use function: file_get_contents to parse JSON file. You have to go through each and every key-value pairs.
Related
For a setup script I write in PHP (for CLI, not web) I use a settings file as well as other other "content" files.
The settings file is built up like a regular ini-file
[header.subheader.moreheaders...]
keyA = value
keyB = value1|value2|...
"header.subheader.moreheaders..." and "keyX" will form a nested associative array with "value" as a string or "value1|value2|..." as a simple array (0-...).
Thanks to this accepted answer, I got so far that I can split the headers into a recursive array recursively. So far, so good.
However, as the content files shall contain references to these variables, I would like to be able to read out single values from that multi-dimensional array with string placeholders like $#R[header.subheader.moreheaders.key] or $#R[header.subheader.moreheaders.key.0] depending on them being a string or an array.
In the script, $#R[header.subheader.moreheaders.key.0] should convert into $SettingsVar[header][subheader][moreheaders][key][0] to return the appropriate value.
Neither the script nor the content files will know what is inside the settings file. The script just knows the general structure and placeholder $#R[...].
This answer appears to know what value will be in order to search for it.
Since I do not fully understand this answer, I am not sure if that would be the right way.
Is there a similar easy way to get the reverse from building that array?
After some contemplation, I found a decent enough solution, which works for me (and hopefully others):
function GetNestedValue($aNestedKeys, $aNestedArray)
{
$vValue = $aNestedArray;
for($i = 0; $i < count($aNestedKeys); $i++)
{
if(array_key_exists($aNestedKeys[$i], $vValue))
{
$vValue = $vValue[$aNestedKeys[$i]];
}
else
{
$vValue = null;
break;
}
}
return $vValue;
}
Depending on what $aNestedKeys contain, it will either return a sub-array from $aNestedArray, a single value from it or null if any of the specified keys were not found.
not sure what I'm doing wrong here but i have my Json string and I'm trying to get the values to print out in the IF statement
i.e:
63,52,55
here is my code:
$jayjay = '{"items":{"cID":"63","qty":"2"},"items":{"cID":"52","qty":"1"},"items":{"cID":"55","qty":"1"}}';
echo $jayjay;
$obj = json_decode($jayjay, TRUE);
for($i=0; $i<=count($obj['items']); $i++) {
echo $obj['items'][$i]['cID'];
echo ",";
}
but the output is just blank and i cant figure out why
Any help would be appreciated.
Thank you
The problem is that you have key "items" multiple time in your JSON which is wrong. Please note that JSON key must be unique for well formed JSON.
Basically there is no error if you use more than one key with the same name, but in JSON, the last key with the same name is the one that is gonna be used. In your case, the key "items" would be better to contain an array of objects as it's value:
{'items' : [{"cID":"63","qty":"2"}, {"cID":"52","qty":"1"}, {"..." : "..."}]}
As Hamish stated in his comment, you can't have json as you've supplied. The keys (which is items in this case) are going to overwrite each other until the last key.
What I suggest is if you create an array like this:
{"items":[{"cID":"63","qty":"2"}, {"cID":"52","qty":"1"},.....]}
Allowing you to itterate as you require.
Meaning you can simply loop as you require:
$items = json_decode($json, true);
foreach($items as $thing){
echo $thing['cID'];
echo ",";
}
As has already been pointed out, your JSON data is malformed.
But since Stack Overflow is a rather inefficient method of syntax checking your data, I would suggest using a JSON linter (such as this one) on static JSON data in the future. Or at the very least, checking the return value of json_last_error after parsing to look for potential problems at least when testing or debugging.
In certain other languages (AS3 for example), it has been noted that initializing a new array is faster if done like this var foo = [] rather than var foo = new Array() for reasons of object creation and instantiation. I wonder whether there are any equivalences in PHP?
class Foo {
private $arr = array(); // is there another / better way?
}
$myArray = [];
Creates empty array.
You can push values onto the array later, like so:
$myArray[] = "tree";
$myArray[] = "house";
$myArray[] = "dog";
At this point, $myArray contains "tree", "house" and "dog". Each of the above commands appends to the array, preserving the items that were already there.
Having come from other languages, this way of appending to an array seemed strange to me. I expected to have to do something like $myArray += "dog" or something... or maybe an "add()" method like Visual Basic collections have. But this direct append syntax certainly is short and convenient.
You actually have to use the unset() function to remove items:
unset($myArray[1]);
... would remove "house" from the array (arrays are zero-based).
unset($myArray);
... would destroy the entire array.
To be clear, the empty square brackets syntax for appending to an array is simply a way of telling PHP to assign the indexes to each value automatically, rather than YOU assigning the indexes. Under the covers, PHP is actually doing this:
$myArray[0] = "tree";
$myArray[1] = "house";
$myArray[2] = "dog";
You can assign indexes yourself if you want, and you can use any numbers you want. You can also assign index numbers to some items and not others. If you do that, PHP will fill in the missing index numbers, incrementing from the largest index number assigned as it goes.
So if you do this:
$myArray[10] = "tree";
$myArray[20] = "house";
$myArray[] = "dog";
... the item "dog" will be given an index number of 21. PHP does not do intelligent pattern matching for incremental index assignment, so it won't know that you might have wanted it to assign an index of 30 to "dog". You can use other functions to specify the increment pattern for an array. I won't go into that here, but its all in the PHP docs.
In ECMAScript implementations (for instance, ActionScript or JavaScript), Array() is a constructor function and [] is part of the array literal grammar. Both are optimized and executed in completely different ways, with the literal grammar not being dogged by the overhead of calling a function.
PHP, on the other hand, has language constructs that may look like functions but aren't treated as such. Even with PHP 5.4, which supports [] as an alternative, there is no difference in overhead because, as far as the compiler/parser is concerned, they are completely synonymous.
// Before 5.4, you could only write
$array = array(
"foo" => "bar",
"bar" => "foo",
);
// As of PHP 5.4, the following is synonymous with the above
$array = [
"foo" => "bar",
"bar" => "foo",
];
If you need to support older versions of PHP, use the former syntax. There's also an argument for readability but, being a long-time JS developer, the latter seems rather natural to me. I actually made the mistake of trying to initialise arrays using [] when I was first learning PHP.
This change to the language was originally proposed and rejected due to a majority vote against by core developers with the following reason:
This patch will not be accepted because slight majority of the core developers voted against. Though if you take a accumulated mean between core developers and userland votes seems to show the opposite it would be irresponsible to submit a patch witch is not supported or maintained in the long run.
However, it appears there was a change of heart leading up to 5.4, perhaps influenced by the implementations of support for popular databases like MongoDB (which use ECMAScript syntax).
Prior to PHP 5.4:
$myArray = array();
PHP 5.4 and higher
$myArray = [];
In PHP an array is an array; there is no primitive vs. object consideration, so there is no comparable optimization to be had.
What you're doing is 100% correct.
In terms of nice naming it's often done that private/protected properties are preceded with an underscore to make it obvious that they're not public. E.g. private $_arr = array() or public $arr = array()
Initializing a simple array :
<?php $array1=array(10,20,30,40,50); ?>
Initializing array within array :
<?php $array2=array(6,"santosh","rahul",array("x","y","z")); ?>
Source : Sorce for the code
There is no other way, so this is the best.
Edit: This answer is not valid since PHP 5.4 and higher.
Try this:
$arr = (array) null;
var_dump($arr);
// will print
// array(0) { }
Do not do this:
$arrTst = array( 'IdxKeyOne' => null, 'IdxKeyTwo' => null, 'IdxKeyThr' => null );
There's no such thing as "initializing" an array's index-keys with dummy/placeholder values. print_r gives:
Array (
[IdxKeyOne] =>
[IdxKeyTwo] =>
[IdxKeyThr] =>
)
where the elements exist, having defined keys but null-values. When using the array later, you would have to drop the dummy-row anyway.
I create this output with PHP:
foreach ($bk as $blink) {
$out["url"][] = $blink->url;
$out["anchor"][] = $blink->anchor;
}
$json = Zend_Json::encode($out);
echo ($json);
I want to receive and process the output with a $.ajax call.
Could you point me to a nice tutorial about multidimensional arrays with javascript/jquery or help me loop* through the json results? I got a bit confused with it.
I am trying to put those on a table, so I will be using <td>url-i</td><td>anchor-i</td> . This part, I figured out how. To put the correct values on url-i and anchor-i is the problem.
I would imagine the JSON output for that will be something like:
{'url': ['url1', 'url2', ... ],
'anchor': ['anchor1', 'anchor2', ... ]}
If that is the case, then they will be of equal length (and importantly equal indexes) and you can loop through one of the two using jQuery.each().
$.getJSON('jsonapp.php', function(data) {
$.each(data.url, function(index, url) {
var anchor = data.anchor[index];
$('#mytable').append('<tr><td>' + url + '</td><td>' + anchor +'</td></tr>');
});
});
I've not run that code, so it might have a few flaws, but that's the gist of it.
PHP can try to cast objects into arrays by itself, and for simple stuff, it usually works fine.
As for multidimensional arrays, Javascript isn't too different from most other higher-level programming/scripting languages when it comes to arrays. Really, any tutorial online on multidimensional arrays will do just fine. A multidimensional array is simply an array of arrays.
When you receive the string client-side, you just want to parse it. jQuery has its own method, but you can use JSON.parse. Afterwards, based on how you've set up your arrays, you'd want to do something like this.
<? $count = count($json_parsed['url']); for($i = 1; $i < $count; $i++) : ?>
<td><?=$json_parsed['url'][$i];?></td>
<td><?=$json_parsed['anchor'][$i];?></td>
<? endfor; ?>
This may be philosophically not the best way to do it though. If you have a whole bunch of objects and you want to make a table out of them, the best way would be to create an array of those objects as represented by associative arrays (sort of like hash tables in other programming languages). PHP natively tries to convert objects into associative arrays. I wouldn't be surprised if Zend_Json::encode does it automatically. If it does, you might want to pull simply:
echo Zend_Json::encode($bk);
If not, let me know, and we'll talk about how to do that.
You could have a look on any template frameworks, but for this exact case it seams useful to check one of those two: pure by beebole or jquery pure html templates.
Doing it by yourself might be tempting but why to reinvent the well - I know from my experience, that frameworks are about 2 times faster, then self made code.
I want to transform the 'values' array created by xml_parse_into_struct() into a bunch of nested arrays which I can walk recursively. This is for a very simple XML class which will hierarchically search the document like so:
$xml_data = "
<sometag>
<someothertag>
<somedata>foo</somedata>
</someothertag>
<someothertag>
<somedata>bar</somedata>
</someothertag>
</sometag>
<sometag>
<someothertag>
<somedata>baz</somedata>
</someothertag>
</sometag>";
$parser = new Xml_Data($xml_data);
$somedata = $parser->find('sometag')->find('someothertag')->results();
// 0: "somedata"
// "value": "foo"
// 1: "somedata"
// "value": "bar"
// etc.
storing it in nested associative arrays would make it much easier to work with than keeping track of each opening and closing tag and what 'level' they occur at like xml_parse_into_struct outputs. But I wonder -- if the document gets pretty big, will this huge array be horrible? Should I just give up and traverse the stupid version of the array that PHP gives me?
Why not to use SimpleXML for that? The same nesting model, but objects instead of arrays.
For best effect you'd might wanna do
$xml['sometag'][0]['someothertag'][1]['somedata'][0] # bar
Where the array has two dimensions for each level. That is, pairs of tagname/tagindex values.
This is both scalable and readable.
Not sure about your exact requirement but I think you can use array_walk_recursive there.