I have a "Array to string conversion" notice for this line when i upgrade from 5.6 to 7.1 :
$template = $this->$functions[$i]($name, $value);
how i could resolve it in order to work with php7.1 ?
UPDATE :
protected function getobjectTemplate($name, $value)
{
$template = false;
$functions = [
'getObjectFormClientTemplate',
'getObjectFormTemplate',
'getObjectAirformTemplate',
'getTypeAirformTemplate',
'getAirfileTemplate',
'getTextAirformTemplate',
];
$i = 0;
while (!$template) {
$template = $this->$functions[$i]($name, $value);
++$i;
}
return $template;
}
here the call of the method getobjectTemplate
$template = $this->getobjectTemplate($name, $value);
This can be one of the solutions. First store the function name in a variable and then use it.
while (!$template) {
$temp=$functions[$i];
$template = $this->$temp($name,$values);
++$i;
}
I am not sure if this is the most elegant solution but it would work:
protected function getobjectTemplate($name, $value)
{
$template = false;
$functions = [
'getObjectFormClientTemplate',
'getObjectFormTemplate',
'getObjectAirformTemplate',
'getTypeAirformTemplate',
'getAirfileTemplate',
'getTextAirformTemplate',
];
$i = 0;
while (!$template) {
$func = [ $this, $functions[$i] ];
$template = $func($name, $value);
++$i;
}
return $template;
}
I would probably also go ahead and remove the while (!template) condition as it has the potential to make your code enter into an infinite loop. Probably use a better condition like $i < count($functions) or even better with something like:
$i = 0;
$funcCount = count($functions);
while(!$template && $i < $funcCount){
# ...
++$i;
}
Also, you are returning only the last value from all the functions being called via return $template. If you only have to return the last value, why not call only the required function and not have a loop. Not sure, if having a loop is the best approach. Would help if you provided more details of your code.
Related
I can easily write to and read from a sub-array in the session array.
$_SESSION['a']['b']['c']['value']=123;
$val=$_SESSION['a']['b']['c']['value'];
Instead of hard coding the "location" where the value is written, I would like it to be definable via a string or some other way. The following will obviously not work, but hopefully will better explain the intent.
$prefix="['a']['b']['c']"; //defined in config page, etc
$_SESSION.$prefix.['value']=123;
$val=$_SESSION.$prefix.['value'];
How can this be accomplished?
PropertyAccess
There is an excellent Symfony component for such tasks, named PropertyAccess. You can use it as follows:
$persons = array('a' => array('b' => 5.7));
$accessor = PropertyAccess::createPropertyAccessor();
echo $accessor->getValue($persons, '[a][b]'); // 5.7
You can install it using Composer as described in docs or fetch directly from GitHub.
Custom solution
This is a complete solution, I'm really impressed that it works... but it works! Check the code below, assert()'s demonstrate the usage:
<?php
function arrayPropertyPathGet(array $arr, $path) {
$parts = explode('.', $path);
$ret = $arr;
foreach($parts as $part) {
$ret = $ret[$part];
}
return $ret;
}
function arrayPropertyPathSet(array &$arr, $path, $value) {
$parts = explode('.', $path);
$tmp = &$arr;
foreach($parts as $part) {
if(!isset($tmp[$part])) { return false; }
$tmp = &$tmp[$part];
}
$tmp = $value;
return true;
}
$test = array('a' => array('b' => 'value'));
assert('value' === arrayPropertyPathGet($test, 'a.b'));
assert(true === arrayPropertyPathSet($test, 'a.b', 'other'));
assert('other' === arrayPropertyPathGet($test, 'a.b'));
Side note
As a theoretical side note (do not use this for anything other than learning purposes) you can experiment with eval(), such as:
eval("$value = $persons['a']['b']");
I faced the same problem a few times ago, and as I didn't find any solution, I made one by myself, if that can help you in anyway (only the interesting part) :
class ArrayAccessor {
private $prefix;
function setPrefix() {
$this->prefix = array();
for ($i = 0; $i < func_num_args(); ++$i) {
$this->prefix[] = func_get_arg($i);
}
}
function getFromPrefix(array $array) {
$tmp_array = $array;
foreach ($this->prefix as $pre) {
if (isset ($tmp_array[$pre])) {
$tmp_array = $tmp_array[$pre];
} else {
return null;
}
}
return $tmp_array;
}
}
$Access = new ArrayAccessor();
$Access->setPrefix('Hi', 'Toto');
$MyTestArray['Hi']['Toto'] = 'Works';
var_dump ($Access->getFromPrefix($MyTestArray));
$Access->setPrefix('Hi');
var_dump ($Access->getFromPrefix($MyTestArray));
$Access->setPrefix('No');
var_dump ($Access->getFromPrefix($MyTestArray));
Result :
string(5) "Works"
array(1) {
["Toto"]=>
string(5) "Works"
}
NULL
I'm using array_filter with multiple parameters but it's not doing the filter correctly. Here where it's supposed to return an array with only "arts,crafts,designs" as an element, it's returning an empty array. The only $askedcat parameter it works for is "arts". I can't find out what the issue is.
I've tried not using an array_filter and instead just looping over the array, and I get the same problem.
<?php
class CategoryFilter {
public $categoryAskedFor;
function __construct($askedCat) {
$this->categoryAskedFor = $askedCat;
}
function categoryCallback($projectCategoryString) {
$project_category_array = explode(",", $projectCategoryString);
if(in_array($this->categoryAskedFor, $project_category_array)) return true;
return false;
}
}
$verifiedProjects = ["arts", "arts,crafts,designs", "film", "film,theater"];
$askedCat = "crafts";
$newArr = array_filter($verifiedProjects, array(new CategoryFilter($askedCat), "categoryCallback"));
for ($i = 0; $i < count($newArr); $i++) {
echo $newArr[$i] . "<br>";
}
I expect the output here to be arts,crafts,design<br> but it's only <br> meaning the array is empty.
There are many way to achieve this but let me show you two way here
WAY #1
If you using the for loop to retrieve the array value then need to have numeric key and as per your code you need array_values function to manage that
<?php
class CategoryFilter {
public $categoryAskedFor;
function __construct($askedCat) {
$this->categoryAskedFor = $askedCat;
}
function categoryCallback($projectCategoryString) {
$project_category_array = explode(",", $projectCategoryString);
if(in_array($this->categoryAskedFor, $project_category_array)) return true;
return false;
}
}
$verifiedProjects = ["arts", "arts,crafts,designs", "film", "film,theater"];
$askedCat = "crafts";
$newArr = array_filter($verifiedProjects, array(new CategoryFilter($askedCat), "categoryCallback"));
$newArr = array_values($newArr);
for ($i = 0; $i < count($newArr); $i++) {
echo $newArr[$i] . "<br>";
}
WAY # 2
If you don't want to use the array_values here then you need to manage the foreach loop instead of for loop
<?php
class CategoryFilter {
public $categoryAskedFor;
function __construct($askedCat) {
$this->categoryAskedFor = $askedCat;
}
function categoryCallback($projectCategoryString) {
$project_category_array = explode(",", $projectCategoryString);
if(in_array($this->categoryAskedFor, $project_category_array)) return true;
return false;
}
}
$verifiedProjects = ["arts", "arts,crafts,designs", "film", "film,theater"];
$askedCat = "crafts";
$newArr = array_filter($verifiedProjects, array(new CategoryFilter($askedCat), "categoryCallback"));
foreach ($newArr as $value) {
echo $value . "<br>";
}
The way you're looping over your resulting array is wrong, because array_filter will preserve the array keys. The 0 index may not be there in the filtered version (and in your case, it actually isn't).
Use foreach instead:
foreach ($newArr as $value) {
echo $value, '<br>';
}
array_filter will remove elements but will not reset the keys. use array_values to reset the keys first.
$newArr = array_values($newArr);
for ($i = 0; $i < count($newArr); $i++) {
echo $newArr[$i] . "<br>";
}
You will get as per your output
$askedCat = 'crafts';
$verifiedProjects = ["arts", "arts,crafts,designs", "film", "film,theater"];
$newArr = array_filter($verifiedProjects, function ($item) use ($askedCat) {
if (stripos($item, $askedCat) !== false) {
return true;
}
return false;
});
foreach ($newArr as $value) {
echo $value . "<br>";
}
In PHP we can do things like these:
Class Example {
...
}
$example = 'Example';
$object = new $example();
Or the use of variable variables:
$hour = 18;
$greets = array('Good morning','Good afternoon','Good evening');
$values = array(13,21,23);//people is sleeping at 23PM, so they don't greet.
$n = count($values);
$greet = 'greets';
for($i=0;$i<$n;$i++){
if($hour < $values[$i]){
echo 'hello, '.${$greet}[$i];
break;
}
}
And others..
I wonder if it would be possible to access directly to a specific index of a multidimensional array in a similar way. Something like:
$array = array(...); //multidimensional array.
$position = '[0][4][3]';
print_r($array$position);
Thanks in advance.
UPDATE
I'm so sorry because I finished my question in a wrong way.
I need to set the multimesional array and add a value. i.e:
$array$position = $data;
You could implement it yourself with a custom function:
function getValueFromMultiDimensionalArray( array $array, string $key )
{
$keys = explode('][', $key);
$value = $array;
foreach ($keys as $theKey) {
// remove the opening or closing bracket if present
$theKey = str_replace([ '[', ']' ], '', $theKey);
if (!isset($value[$theKey])) {
return null;
}
$value = $value[$theKey];
}
return $value;
}
You can define path as dot separated , check the following solution
function getValueByKey($a,$p){
$c = $a;
foreach(explode('.',$p) as $v){
if(!array_key_exists($v, $c)) return null;
$c = $c[$v];
}
return $c;
}
You can use this function as
$path = '1.2.3.0';
$indexValue = getValueByKey($array, $path);
Nope, this is not possible.
The only thing you can do is to implement ArrayAccess interface, which allows to access instances with [] operator. But you will have to define the logic yourself.
class MyClass implements ArrayAccess
{
...
}
$x = new MyClass([0=>[4=>[3=>'hello world']]]);
$position = '[0][4][3]';
echo $x[$position]; //hello world
I have a class Tpl to mount template with this function (template.php)
function Set($var, $value){
$this->$var = $value;
}
A php file that call the function, example (form.php):
$t->Set("lbAddress","Address");
And a html file with the template with tags (template.html)
<tr><td>[lbAdress]</td></tr>
To print the html I have this function (template.php) - the notice points to this function
function Show_Temp($ident = ""){
// create array
$arr = file($this->file);
if( $ident == "" ){
$c = 0;
$len = count($arr);
while( $c < $len ){
$temp = str_replace("[", "$" . "this->", $arr[$c]);
$temp = str_replace("]", "", $temp);
$temp = addslashes($temp);
eval("\$x = \"$temp\";");
echo $x;
$c++;
}
} else {
$c = 0;
$len = count($arr);
$tag = "*=> " . $ident;
while( $c < $len ){
if( trim($arr[$c]) == $tag ){
$c++;
while( (substr(#$arr[$c], 0 ,3) != "*=>" ) && ($c < $len) ){
$temp = str_replace("[", "$" . "this->", $arr[$c]);
$temp = str_replace("]", "", $temp);
$temp = addslashes($temp);
eval("\$x= \"$temp\";"); //this is the line 200
echo $x;
$c++;
}
$c = $len;
}
$c++;
}
}
}
If the template .html have a line [lbName] and I don't have the line $t->Set("lbName","Name"); at the php code, I receive the error PHP Notice: Undefined property: Tpl::$lbName in ../template.php(200) : eval()'d code on line 1. The solution that I found is add lines like $t->Set("lbName","");, but if I have 50 tags in HTML that I don't use in PHP, I have to add all 50 $t->Set("tag_name","");. The error occurred after migrate to the PHP 5.
Can someone help me? Thanks
Perhaps a better way still would be not to rely on dynamic evaluation through eval (it's generally best to avoid eval where possible), but to replace [lbName] with the value stored in the object directly as and when needed. If you can replace [lbName] with $this->lbName, surely you can also replace it with the value of lBName that you've looked up on-the-fly?
To answer your original question, however:
If I understand correctly, you're setting the values like this:
$t->Set('foo', 'bar');
And – effectively – getting them like this:
$t->foo;
If so, you could implement a __get method to intercept the property references and provide your own logic for retrieving the value; e.g.:
public function __get($key)
{
// You can adapt this logic to suit your needs.
if (isset($this->$key))
{
return $this->$key;
}
else
{
return null;
}
}
In this case, you'd probably be better off using an associative array as the backing store, and then using __get and __set to access it; e.g.:
class Template
{
private $values = array();
public function __get($key)
{
if (array_key_exists[$key, $this->values])
{
return $this->values[$key];
}
else
{
return null;
}
}
public function __set($key, $value)
{
$this->values[$key] = $value;
}
}
How to send an indexes name for php array vairable.
the array is
$array = array('Somthing'=>array('More'=>array('id'=> 34)));
and now I want to display this thing but with a variable name I don't know how to explain so I write what I want to have.
$index_name = '[Something][More][id]';
$array{$index_name};
Is it possible in any way ?
Not in one go like that. Here's how you'd do it:
$array['Something']['More']['id']
If you particularly wanted access multidimensional arrays with a single string, then you could build a function to do that:
function array_multi(Array $arr, $path) {
$parts = explode(".", $path);
$curr =& $arr;
for ($i = 0, $l = count($parts); $i < $l; ++$i) {
if (!isset($curr[$parts[$i]])) {
// path doesn't exist
return null;
} else if (($i < $l - 1) && !is_array($curr[$parts[$i]]) {
// path doesn't exist
return null;
}
$curr =& $curr[$parts[$i]];
}
return $curr;
}
// usage:
echo array_multi($array, "Something.More.id"); // 34
echo array_multi($array, "Something.More"); // array("id" => 34)
Recursive version supporting your syntax with square brackets:
$array = array('Something'=>array('More'=>array('id'=> 34)));
$string = '[Something][More][id]';
echo scan_array($string, $array);
function scan_array($string, $array) {
list($key, $rest) = preg_split('/[[\]]/', $string, 2, PREG_SPLIT_NO_EMPTY);
if ( $key && $rest ) {
return scan_array($rest, $array[$key]);
} elseif ( $key ) {
return $array[$key];
} else {
return FALSE;
}
}
Ok, I know this is how people get shot. But c'mon, eval() is not always the wrong answer.
$array = array('Something'=>array('More'=>array('id'=> 34)));
$index_name = '[Something][More][id]';
eval('$val = $array'.$index_name.';'); // Wrap in a function or something
You could do this with eval():
<?php
$array = array('Somthing'=>array('More'=>array('id'=> 34)));
$index_name = "['Somthing']['More']['id']";
$stmt='echo $array'.$index_name.';';
eval($stmt);
?>
UPDATE:
It seems some SO users are uncomfortable with the idea of using eval(). I think it makes sense to read this thread which discusses the pros and cons before deciding whether to use this in your own code.
If you've cornered yourself into needing to do something like this, there's a pretty good chance you've done something else in a poor way. There's valid reasons to do this, but not very often.
function key_path($arr, $keys) {
return $keys ? key_path($arr[array_shift($keys)], $keys) : $arr;
}
$arr['Something']['More']['id'] = 34;
$keys = array('Something', 'More', 'id');
var_dump( key_path($arr, $keys));