I am working in WordPress. I am using a plugin to get the admin options. The plugin takes an argument as an ID to get the value from the database like so.
$option = ot_get_option('email_address');
The above line of code would return
myEmail#example.com
I want to write a helper function that would get multiple values at once. Normally, I would get the options like this.
$option_1 = ot_get_option('option1');
$option_2 = ot_get_option('option2');
$option_3 = ot_get_option('option3');
I figured there could be a better way that would look a little nicer. I put together this little function that does work
function ritual_get_options($arg_list = array())
{
$options = array();
foreach( $arg_list as $key => $value){
$options[] = ot_get_option($value, array());
}
return $options;
}
using the function above, I can now pass the id's of the options like so
ritual_get_options('option1','option2','option3');
My issue is that the above will return an array with numeric keys. 0,1,2. Here is the exact array that is getting returned when I do a var_dump on the front end
[0]=>
string(16) "100 Main Street,"
[1]=>
string(18) "Hamilton, Ontario."
[2]=>
string(15) "+1 800 999 9898"
[3]=>
string(19) "mail#yourdomain.com"
I want to return the array keys with the value so that I can easily figure out what value is in what key. Here is the line that I used to get the above array
$options = ritual_get_options(array('number' => 'streetnumber','street' => 'street','phone' => 'phone_number','email' => 'email'));
When I go to use the returned values, I want to be able to use the key so that I could do
echo $options['number'];
instead of doing
echo $options[0];
I have not been able to figure out how to return the keys passed in to the function and preserve them into through the return.
Set the option name as key while building the array:
foreach( $arg_list as $option ){
$options[$option] = ot_get_option( $option );
}
Btw, using extract() on the $options array will allow you to use e.g. $phone_number instead of $options['phone_number']
Related
I have this JSON data that is set up as an array of objects that looks like this, where the keys are literally called "key" and the values are literally called "value":
$fruit = [{"key": "a", "value": "apple"},
{"key": "b", "value": "banana"},
{"key": "c", "value": "cherry"}];
I am trying to write a PHP function that takes in this array as an argument, along with the key I want to look up.
The function should act as a lookup so that the function will return the value associated with the provided key. For example:
function lookup($array, $key){
// look through the list of objects and
// return value that is associated with this key
}
Example function call:
lookup($fruit, "c");
Expected output:
"cherry"
I am new to PHP, so I don't know if PHP has a best practice or native function that would make easy work of this, or should I iterate through the $fruit array and build a new PHP array with it first? What is the best way to do this?
Using PHP 7.0+ you can use array_column on an array of objects.
Providing the second argument as the property name to retrieve values from, and then using the third argument to specify the property name to index by, will provide you with a full list of values indexed by the specified key.
Example https://3v4l.org/vJcmH
$values = array_column($json, 'value', 'key');
var_dump($values);
/*
array(3) {
["a"]=>
string(5) "apple"
["b"]=>
string(6) "banana"
["c"]=>
string(6) "cherry"
}
*/
var_dump($values['c']);
/*
string(6) "cherry"
*/
Function usage https://3v4l.org/8TMBf
/**
* #param array|object[] $json
* #param string $key
* #param mixed $default
* #param string $column
* #param string $index
* #return string
*/
function lookup($json, $key, $default = '', $column = 'value', $index = 'key') {
return array_column($json, $column, $index)[$key] ?? $default;
}
var_dump(lookup($json, 'c'));
Result:
string(6) "cherry"
Note, this will return a single value, if you are expecting to have
more than 1 result with the same key property value, this approach
will not yield expected results. If so please let me know and I will update my answer.
Convert your JSON string to a PHP array
$fruit = json_decode($fruit, true);
lookup($fruit, 'key');
Then, you just have to loop through the array in your function.
function lookup($array, $key) {
//loop through all values in array
foreach($array as $values) {
//if 'key' value matches `$key`, return 'value' value.
if($values['key'] == $key) {
return $values['value'];
}
}
//if nothing has been returned, return empty string
return "";
}
Now, if you have control over creating the $fruit value, it would be better to create it in this pattern:
$fruit = [
"a" => "apple",
"b" => "banana",
"c" => "cherry",
];
then you can access it with:
$fruit[$key];
Something like this would work.
https://ideone.com/94Uxby
<?php
$fruit = json_decode($sourceOfJson, true);
function lookup($array, $key){
// Find the index of the entry where "key" = $key
$index = array_search($key, array_column($array, 'key'));
// Handle the entry not being found however you want to.
if(!$index){
return null;
// throw new Exception("Couldn't find index from value $key");
// Log::error("Couldn't find index from value $key");
// return 'SomeDefaultValue';
}
return $array[$index]['value'];
}
echo lookup($fruit, 'c');
I'm stuck with a very weird bug. I have an object called $row that looks like this:
stdClass Object
(
[title] => Some Title
[body] => My body
[topic] => Topic
[dataType] => Survey
[csvrownum] => 1
)
I'm just trying to print out the title property in the following way:
print_r($row->title);
However for some reason that doesn't output anything.
Then I've tried to manually set the title property and print it right after, something like this:
$row->title = 'My Title';
print_r($row->title);
Surprisingly it worked but why? To make this more strange I decided to var_dump the object after set the title variable by hand:
$row->title = 'My Title';
var_dump($row);
And this is what I've got:
class stdClass#391 (6) {
public $title =>
string(3) "Some title"
public $body =>
string(7) "My body"
public $topic =>
string(6) "Topic"
public $dataType =>
string(17) "Survey"
public $csvrownum =>
int(1)
public $title =>
string(8) "My title"
}
Notice the title key is duplicated with different values. Is there any condition under this could happen?
No, PHP does not allow an object to have duplicate property names, because objects in PHP are implemented just like arrays. They are both implemented as ordered hashmaps. In a hashmap, two things that have the same hash, overwrite each other.
You likely just have unprintible characters in your object property name. You can see this more clearly by doing something like the following for debug purposes...
foreach($row as $key => $value) {
var_dump($key);
}
If we had an object like this, for example, you'd see it gets overwritten.
$row = new stdClass;
$row->title = "First";
$row->title = "Second";
But something like this might be more deceptive...
$row = new stdClass;
$row->{"title\0"} = "First";
$row->title = "Second";
Output from the foreach using var_dump on the key, would reveal this...
string(6) "title"
string(5) "title"
Notice one is string of length 6 and the other is a string of length 5.
Grain of salt
It's always better to use var_dump when attempting to debug variables than using something like print_r, as var_dump was specifically designed for debug purposes, whereas print_r is just a recursive print (hence the name). Printing values like null, false, or empty strings, gives you no useful information for debug purposes, but var_dump does.
Given the following array:
$array = array(
'item_1' => array(
'item_1_1' => array(
'item_1_1_1' => 'Hello',
),
'item_1_2' => 'World',
),
'item_2' => array(),
);
How can I convert that into an Object?
Option 1
$obj = (object) $array;
Or
Option 2
$object = json_decode(json_encode($array), FALSE);
Or something else?
I would like to know the difference in the output between the 2 option and understand the best practice for creating this conversion.
Well you are answering somehow your own question, but if you want to have an object with the attributes like your array you have to cast it, this way an array will remain an array
$obj = (object) $array;
OUTPUT:
object(stdClass)#1 (2) {
["item_1"]=>
array(2) {
["item_1_1"]=>
array(1) {
["item_1_1_1"]=>
string(5) "Hello"
}
["item_1_2"]=>
string(5) "World"
}
["item_2"]=>
array(0) {
}
}
if you are using the json_decode version it will convert arrays to objects too:
object(stdClass)#2 (2) {
["item_1"]=>
object(stdClass)#3 (2) {
["item_1_1"]=>
object(stdClass)#4 (1) {
["item_1_1_1"]=>
string(5) "Hello"
}
["item_1_2"]=>
string(5) "World"
}
["item_2"]=>
array(0) {
}
}
NOTE: just the empty array will be an array here.
To Answer your question: The best practice depends on what YOU need.
It depends, really: if you are working on data that might be an array in one case, and an object the next, it would probably be best to use the json_decode trick, simply because unlike a cast, its result is "recursive". There is one very important thing to keep in mind here, though: numeric indexes can, and probably will cause problems for you at some point in time. Take a look at this bug report
This is documented here, but not in a way that really stands out:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible;
Exampe of the problem:
$data = [
'foo' => 'bar',
123 => 'all is well',
];
$obj = json_decode(json_encode($data));
var_dump($obj->foo);//bar
var_dump($obj->{123});//all is well
$cast = (array) $obj;
var_dump($cast);//shows both keys
var_dump(isset($cast[123]));//FALSE!!!
var_dump(isset($cast['123']));//FALSE
Basically: If you start converting arrays to objects and back again, numeric keys are not reliable anymore. If I were you, I'd simply change the code that is passing the data where possible, or I'd create a value object that can be set using an array or an object, and normalize the data that way.
I'm working on a project in CodeIgniter 2 and now I'm stuck on the most basic of concepts.
Model:
Get an object array from my table which contains all rows that match a specific value for a field named foo. There can be one or more rows that match. In this example, two rows.
public function get_sample($foo)
{
$query = $this->db->get_where('sample_db', array('foo' => $foo));
return $query->result();
}
Controller:
Assign the results and make output available to view.
public function view($foo)
{
$data['array'] = $this->sample_model->get_sample($foo);
$this->load->view('view', $data);
}
View:
echo var_dump($array); // for testing
echo $array[1]->text
var_dump() of $array:
array(2) {
[0]=> object(stdClass)#23 (4) {
["id"]=> string(1) "1"
["foo"]=> string(3) "bar"
["number"]=> string(4) "1234"
["text"]=> string(23) "This is content in 1234"
}
[1]=> object(stdClass)#24 (4) {
["id"]=> string(1) "2"
["foo"]=> string(3) "bar"
["number"]=> string(4) "9999"
["text"]=> string(23) "This is content in 9999"
}
}
The rendered ouput of echo $array[1]->text; is: This is content in 9999
And I understand how all that is working: $array[1]->text is the content of the text field in the array object with the index of 1, my second object.
However, I have a field called number and I want to access the object with a certain number and get its corresponding text value.
Example: How can I retrieve the value of text where the number is 9999? I cannot use $array[1]->text since I can never be sure of the object's position in the array. Something like $array['number' => '9999']->text, but I know that's not right. Maybe I need to loop through the array looking for a match?
This looks so simple yet everything I've tried has failed and resulted in various PHP errors. I've been studying the PHP manual here and here, but cannot seem to find anything about what I'm looking to do, or maybe I'm just misapplying what I'm reading. Any guidance is appreciated.
In addition to an answer using best practices following the MVC model, I'm hoping for a link to the proper page in the documentation, as well as pointing out any errors in my wording/terminology above.
EDIT:
This answer contains the actual code I used to solve my problem. Although, Yagi's answer was accepted because it put me in the right direction.
How about using this :
foreach ($array as $row) {
if ($row->number == '9999') {
echo $row->text;
}
}
Loop through the array, and find the number object value of 9999 and get the text
Why don't you just to a query and search for that number (or order by that number?)
Either way, what you need is a multidimensional array search function (that iterates through array of object and returns the found field value combo )
Something like this (put this in helper)
function multi_array_search($array, $field, $value)
{
$results = array();
if (is_array($array))
{
if ($array->$field == $value) //chek the filed against teh value, you can do addional check s(i.e. if field has been set)
$results[] = $array;
foreach ($array as $subarray)
$results = array_merge($results, multi_array_search($subarray, $key, $value)); //recurisve serach
}
return $results;
}
//than in view or in controller, depending where you need it
$result = multi_array_search($array, "number", "9999");
var_dump($result) will return or whether number of foudn instances
array() {
[0]=> object(stdClass)#24 (4) {
["id"]=> string(1) "2"
["foo"]=> string(3) "bar"
["number"]=> string(4) "9999"
["text"]=> string(23) "This is content in 9999"
}
}
you might be looking for something like this...
array_filter($array, function($o){ return $o->number == 9999; } );
http://php.net/manual/en/function.array-filter.php
EDIT
$o is the parameter in the callback function. each element of the array is passed to the callback function. if the function returns false, the element will be filtered out.
$arr = array(
(object) array(
'num' => 33,
'text' => 'hello',
),
(object) array(
'num' => 44,
'text' => 'world',
),
);
$filtered = array_filter($arr, function($o){ return $o->num == 33; });
echo $filtered[0]->text; // hello
as you stated, index will remain, so use array_values or array_shift. here's an example with function
function get_by_num($arr, $num){
return array_shift(array_filter($arr, function($o) use ($num) { return $o->num == $num; }));
}
$obj = get_by_num($arr, 44);
var_dump($obj);
// object(stdClass)#2 (2) { ["num"]=> int(44) ["text"]=> string(5) "world" }
in this case $obj will be either NULL if element is not found, or the first match. $num is transferred along so you can use any value. you can even improve it:
function get_first_match($arr, $field, $val){
return array_shift(array_filter($arr, function($o) use ($field, $val) { return $o->{$field} == $val; }));
}
$obj = get_first_match($arr, 'num', 44);
and now you can search any field. in your case
$obj = get_first_match($array, 'number', 9999);
Thanks to Yagi's answer, I came up with the following very simple solution. I loop through the array and assign the value of text to a new array with an index that matches the value of number. Then in the view file, I can access the text value based on this index.
Controller:
public function view($foo)
{
$data['array'] = $this->sample_model->get_sample($foo);
foreach ($data['array'] as $row) {
$data['result'][$row->number] = $row->text;
};
$this->load->view('view', $data);
}
View:
if (isset($result[9999])) echo $result[9999];
I have a html form with checkboxes. Someone selects one or more checkboxes and hit the delete button then it will delete the files references out of the database and delete the files out of Amazon S3. This is the code I used to find all the checkboxes
$checkbox_select = JRequest::getVar('checkboxselect', '', 'POST'); //just a Joomla way of doing a $_POST with extra security
var_dump($checkbox_select); //this returns: array(2) { ["video_1.mp4"]=> string(2) "on" ["video_2.mp4"]=> string(2) "on" ["video_3.mp4"]=> string(2) "on"}
// Localize and sanitize each individual value
foreach (array_keys($checkbox_select) as $element) {
$deleteNames[] = $db->quote($element);
}
var_dump($deleteNames); //array(3) { [0]=> string(13) "'video_3.mp4'" [1]=> string(13) "'video_2.mp4'" [2]=> string(13) "'video_1.mp4'" }
My problem is with Amazon S3 and multiple file deletion. The format I need to put S3 deletion in is quite confusing:
$s3->delete_objects('mybucket', array(
'objects' => array( // accepts a *list* of one or more *hashes*
// a *hash* that contains a "key" key with a value, and maybe a "version_id" key with a value
array('key' => 'object (file) name'),
// a second hash representing a file
// a third hash representing a file
// and so on...
),
));
As far as I understand (from S3 delete_objects function) the final associated array has key as the actual key value. With the last var_dump I've got all video names in an array now I just need to convert that array to a bunch of arrays in this format:
array ('key' => 'video_1.mp4'),
array ('key' => 'video_2.mp4'),
array ('key' => 'video_3.mp4'),
...and so on
How can I create these arrays? Should I be using the first var_dump I have or the second (they both have the video file names listed)? Thanks in advance.
You can use foreach to loop over your array and create a new array in the desired format.
Example:
<?php
foreach (array_keys($checkbox_select) as $element) {
$deleteNames[] = array('key' => $db->quote($element));
}
Untested, may contain errors
have a look at this post in the php documentation for array_push(). You'll get a brief idea of how to achieve it.