How can I fix this method to accept reference passing?
It throws Fatal error:Only variables can be passed by reference.
/**
* Set a value "deep within" an associative array.
*
* #param array $array_ - Target array to set value on.
* #param mixed $value - A value to set.
* #param string $keyPath - Like 'campaign.pushMessages.sendDate'.
*/
private function setValueForKeyPath(&$array, $value, $keyPath)
{
$keys = explode(".", $keyPath, 2); // Like [ 'campaign', 'pushMessages.sendDate' ]
// If keys is a leaf key...
$isLeaf = (count($keys) == 1);
if ($isLeaf)
{
// ...simply set the value.
$array[$keys[0]] = $value;
}
else
{
// ...or set a sub-array as value.
$this->setValueForKeyPath($array[$keys[0]], $value, $keys[1]);
}
}
Related
I have this variable:
$otcId;
which value can be retrieved from 3 different places(keep in mind this value will always be the same in all places):
$otcId = $this->dat['id_rfcOV'];
$otcId = $this->request['id_rfcOV'];
$otcId = $this->response['id_rfcOV'];
my approach was the following:
$otcId = $this->dat['id_rfcOV'];
if(isset($this->dat['id_rfcOV'])){
$otcId = $this->dat['id_rfcOV'];
} elseif(isset($this->request['id_rfcOV'])) {
$otcId = $this->request['id_rfcOV'];
} elseif(isset($this->response['id_rfcOV'])) {
$otcId = $this->response['id_rfcOV'];
}
what would be a shorter better and more readable way to write this code?
If I were you, I would wrap this in a function, and use the null coalescing operator to simplify retrieval and the return of a default value.
<?php
class MyController
{
private array $dat = [];
private array $request = ['id_rfcOV' => 'foo'];
private array $response = ['id_rfcOV' => 'bar'];
/**
* #param string $name Parameter name
* #param null $default Default value to return if no matching parameters are found
* #return mixed|string|null
*/
function getParam(string $name, $default=null)
{
return $this->dat[$name] ?? $this->request[$name] ?? $this->response[$name] ?? $default;
}
function test(): void
{
// Using a member function, we can get our parameter value with a one-liner
$otcId = $this->getParam('id_rfcOV');
assert($otcId == 'bar', 'Value should be from the last array checked');
printf("Value is %s \n", $otcId);
$val = $this->getParam('non-existent', 'wombats');
assert($val == 'wombats', 'Value should be the default');
printf("Value is %s \n", $val);
}
}
$myController = new MyController();
$myController->test();
If I do this:
$array = ["one", "two", "three"];
$array_copy = "$array"; // or "{$array}"
I doesn't get the original array but instead a string conversion of it. ¿Is there any way to acomplish this task? To get the array reference by his string name.
Thank you.
Edit:
I am aware of this:
$array = ["one", "two", "three"];
$array_copy = $"array";
or
$name = "array";
$array_copy = $$name
But I need to achive this in any situation. Example:
$array = ["one", "two", "three" => ["four"] ];
$sub_array = "{$array['three']}"; // this returns an string, not the array ["four"]
I hope is more clear now.
Edit 2
Let's put it in other way. Imagine you need that an user input (string) be able to access the content of any declared variable. Example:
$customer = [ "name"=>"Peter", "address"=> ["street"=>"5th", "number"=>1969] ];
$variable_name = $_GET["varname"];
var_export( $$variable_name ); // What can write the user to print $customer["address"] array?
because you equal to string, just do it directly
$array_copy = $array
but copy is just copy, not a referense, if you want reference you should write like this
$array_copy = &$array
but there are should be reasons to get the reference
or if you have some variable with array name then you can do like this
$array = ["one", "two", "three"];
$arrayName = 'array';
$array_copy = $$arrayName;
You may use a function that takes a path such as customer.address as a parameter to retrieve the address index of the $customer array automatically:
$customer = ['name' => 'Peter', 'address' => ['street' => '5th', 'number' => 1969]];
/**
* #param array $array
* #param string $path A dot-separated property path.
* #param mixed $default
* #return mixed
*/
function getArrayValue(array $array, string $path, $default = null)
{
$parts = explode('.', $path);
return array_reduce($parts, static function ($value, $part) use ($default) {
return $value[$part] ?? $default;
}, $array);
}
/**
* #param string $path A dot-separated path, whose first part is a var name available in the global scope.
* #param mixed $default
* #return mixed
*/
function getGlobalArrayValue(string $path, $default = null)
{
#list($varName, $propertyPath) = explode('.', $path, 2);
return getArrayValue($GLOBALS[$varName] ?? [], $propertyPath, $default);
}
echo getGlobalArrayValue('customer.name'), PHP_EOL; // Peter
echo getGlobalArrayValue('customer.address.street'), PHP_EOL; // '5th'
echo getGlobalArrayValue('customer.address.idontexist', 'somedefaultvalue'), PHP_EOL; // 'somedefaultvalue'
echo getGlobalArrayValue('idontexist.address', 12); // 12
Demo: https://3v4l.org/O6h2P
Can i get the effect of JSON_NUMERIC_CHECK without JSON?
i.e. Recrusive replacement of numeric strings to ints or floats.
Example with JSON_NUMERIC_CHECK:
<?php
// some input from somewhre
$data = explode(',', 'abc,7,3.14');
echo "Before:"; var_dump($data);
$data = json_decode(json_encode($data, JSON_NUMERIC_CHECK), TRUE);
echo "After:"; var_dump($data);
But I geuss converting to json and back is slow, is there some other way to get the same result?
You can loop over your strings and cast any numeric value to int or float using the following code:
/**
* Normalize an object, array or string by casting all
* numeric strings it contains to numeric values.
*
* #param array|object|string $data
* #return mixed
*/
function normalize($data) {
if (is_array($data))
return array_map('normalize', $data);
if (is_object($data))
return (object) normalize(get_object_vars($data));
return is_numeric($data) ? $data + 0 : $data;
}
$data = "15,2.35,foo";
$data = normalize(explode(',', $data));
// => [15, 2.35, 'foo']
Hope this helps :)
More efficient way
/**
* Normalize an string or object by casting all
* numeric strings it contains to numeric values.
* Note that it changes the variable directly
* instead of returning a copy.
*
* #param object|string $data
* #return void
*/
function normalizeItem(&$data) {
if (is_object($data)) {
$data = get_object_vars($data);
normalize($data);
$data = (object) $data;
} else {
$data = is_numeric($data) ? $data + 0 : $data;
}
}
/**
* Applies normalizeItem to an array recursively.
*
* #param array &$list
* #return bool
*/
function normalize(&$list) {
return array_walk_recursive($list, 'normalizeItem');
}
You can use array_map() with a callback.
$data = explode(',', 'abc,7,3.14');
$re = array_map(function(&$a) {
return ctype_digit($a) ? intval($a) : $a;
}, $data);
var_dump($re);
https://eval.in/715641
I am trying to figure out the best way to use dot notation when passing in a key or set of keys into a function and getting that post value.
Example
shipping.first_name
What it looks like in actual $_POST array:
$_POST[shipping][first_name] = 'some value'
I would like to be able to pass in (as a parameter) the string, and have the function return the post value.
function get_post($str = NULL){
return $_POST[$key1][$key1]..etc.
}
Current attempt (working as intended, but need to put into $_POST):
From: SO Question
function assignArrayByPath(&$arr, $path) {
$keys = explode('.', $path);
while ($key = array_shift($keys)) {
$arr = &$arr[$key];
}
}
$output = array();
assignArrayByPath($output, $str);
This produces an array of:
Array ( [shipping] => Array ( [first_name] => ) )
I would like then to do something like this:
return isset($_POST.$output) ? true : false;
So how do I take that array created from the period separated string and check if it exists in POST?
I think this might be a duplicate, but I am not positive. I apologize in advance if it is. Any help is much appreciated.
See Laravel array_set implement http://laravel.com/api/source-function-array_set.html#319
/**
* Set an array item to a given value using "dot" notation.
*
* If no key is given to the method, the entire array will be replaced.
*
* #param array $array
* #param string $key
* #param mixed $value
* #return array
*/
function array_set(&$array, $key, $value)
{
if (is_null($key)) return $array = $value;
$keys = explode('.', $key);
while (count($keys) > 1)
{
$key = array_shift($keys);
// If the key doesn't exist at this depth, we will just create an empty array
// to hold the next value, allowing us to create the arrays to hold final
// values at the correct depth. Then we'll keep digging into the array.
if ( ! isset($array[$key]) || ! is_array($array[$key]))
{
$array[$key] = array();
}
$array =& $array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}
Check exists you can see array_get http://laravel.com/api/source-function-array_get.html#224
/**
* Get an item from an array using "dot" notation.
*
* #param array $array
* #param string $key
* #param mixed $default
* #return mixed
*/
function array_get($array, $key, $default = null)
{
if (is_null($key)) return $array;
if (isset($array[$key])) return $array[$key];
foreach (explode('.', $key) as $segment)
{
if ( ! is_array($array) || ! array_key_exists($segment, $array))
{
return value($default);
}
$array = $array[$segment];
}
return $array;
}
I am sure this is 100% wrong so if someone could correct me It would be greatly appreciated.
But on the 'index' page it the variable $venuedeets returns a random capitalized letter currently C.
on events function - do I need to set the domain, if so how do I set it as base_url, also is it possible to add custom values and attach them to variables such as venuename => $venue.
$cookie = array(
'name' => 'venue_details',
'value' => 'Hello',
'expire' => time()+86500,
'path' => '/',
);
$this->input->set_cookie($cookie);
index
$this->load->helper('cookie');
$this->input->cookie('venue_details', TRUE);
$cookie2 = get_cookie('venue_details');
$data['venuedeets'] = $cookie2['value'];
Thanks.
The problem is you're misunderstanding how the CI's get/set cookie works (*):
when you set a cookie (either using $this->input->set_cookie() or the equivalent helper function) you pass it an array, but internally that array is used to assign the properties that create the cookie. You're not just serializing an array into a file, you're creating a cookie with a name, set an expiration, and provide some content.
The moment you retrieve the cookie, by passing its name, you get back only its content, because that's the actual,real content of the cookie. Again, it's not a serialized array.
So, coming at your code:
$this->load->helper('cookie');
$this->input->cookie('venue_details', TRUE);
// this line is useless: the method returns a cookie, filtered for XSS, but you're
// assigning it to nothing
$cookie2 = get_cookie('venue_details');
// this your "real" cookie access method
$data['venuedeets'] = $cookie2['value'];
Here is your error: $cookie2 is NOT an array, but a STRING : the cookie's content.
If you var_dump($cookie2), in fact, you get:
string(5) "Hello"
The "random value" problem you encounter is most likely due to the fact that, when trying to access the 'value' index, php typecasts the index (a string) to an integer (0), and fetches the 0 index of the string. In the case of "Hello", you would get "H" - plus a nice Warning if you have the proper error lever for showing it. See it for yourself.
(*) If you're curious, here's how the cookie is accessed (in system/core/Input.php):
/**
* Fetch an item from the COOKIE array
*
* #access public
* #param string
* #param bool
* #return string
*/
function cookie($index = '', $xss_clean = FALSE)
{
return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
}
And here's how is retrieved:
/**
* Fetch from array
*
* This is a helper function to retrieve values from global arrays
*
* #access private
* #param array
* #param string
* #param bool
* #return string
*/
function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
{
if ( ! isset($array[$index]))
{
return FALSE;
}
if ($xss_clean === TRUE)
{
return $this->security->xss_clean($array[$index]);
}
return $array[$index];
}
And how's created:
function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE)
{
if (is_array($name))
{
// always leave 'name' in last place, as the loop will break otherwise, due to $$item
foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item)
{
if (isset($name[$item]))
{
$$item = $name[$item];
}
}
}
if ($prefix == '' AND config_item('cookie_prefix') != '')
{
$prefix = config_item('cookie_prefix');
}
if ($domain == '' AND config_item('cookie_domain') != '')
{
$domain = config_item('cookie_domain');
}
if ($path == '/' AND config_item('cookie_path') != '/')
{
$path = config_item('cookie_path');
}
if ($secure == FALSE AND config_item('cookie_secure') != FALSE)
{
$secure = config_item('cookie_secure');
}
if ( ! is_numeric($expire))
{
$expire = time() - 86500;
}
else
{
$expire = ($expire > 0) ? time() + $expire : 0;
}
setcookie($prefix.$name, $value, $expire, $path, $domain, $secure);
}
$this->load->helper('cookie');
$this->input->cookie('venue_details', TRUE);
// this line is useless: the method returns a cookie, filtered for XSS, but you're
// assigning it to nothing
$cookie2 = get_cookie('venue_details');
// this your "real" cookie access method
$data['venuedeets'] = $cookie2['value'];