I get some data externally but gets this error because the variable is "empty":
Undefined property: stdClass::$summary in /Applications/MAMP/htdocs/jobportal/functions.php on line 68
I have tried to build a function to help me:
$summary = convert_empty($user->summary);
function convert_empty($data) {
if(isset($data)) {
return $data;
} else {
return ".";
}
}
But the error is still there. I have tried isset, empty, and defined. I think I miss another point here - since none of it is working.
That means that the object $user doesn't have a summary member variable defined.
$summary = isset($user->summary) ? convert_empty($user->summary) : NULL;
Or
$summary = isset($user->summary) ? convert_empty(isset($user->summary) ? $user->summary : NULL);
Now you won't see the warning and $summary will be set to NULL, assuming that you're expecting $summary to be NULL in this situation in which $user->summary is undefined.
The second one allows your convert_empty to figure it out.
The issue is not in your function, but how you call it. The error is that you're trying to access ->summary but doesn't exists. You could use something like this:
$summary = convert_empty($user, 'summary');
function convert_empty($data, $key) {
if (isset($data->$key))
return $data->$key;
return ".";
}
Note that you should also test if $data is an object too.
if (is_object($data) && isset($data->$key)) { ... }
Or, without a function using conditional ternary operator :
$summary = isset($user->summary) ? $user->summary : '.';
EDIT for a deeper use :
convert_empty($user, 'positions', 'values', $i, 'title');
function convert_empty($obj) {
$error = '.';
$args = func_get_args();
array_shift($args); // remove $obj
$ref = $obj ;
foreach ($args as $arg) {
if (is_array($ref)) {
if (!isset($ref[$arg])) return $error ;
$ref = $ref[$arg] ;
}
elseif (is_object($ref)) {
if (!isset($ref->$arg)) return $error ;
$ref = $ref->$arg ;
}
}
return $ref ;
}
Related
I'm very new to PHP and Laravel, I'm getting an eror that I can't make head or tail of.
public function filtered($col, $sort = null, $search = null, $ordering='desc')
{
$field = $this->table . '.' . $col ;
Log::info('BaseModel::filtered->' . $field) ;
$data = $this;
// check if search variable not empty
if ($search != null)
{
$data = $data->where(function ($query) use ($search){
return $query->where($field,'like','%'.$search.'%') ;
});
// check if sort variable not empty
if ($sort != null)
{
$sorts = explode('|', $sort);
$data = $data->orderBy($sorts[0],$sorts[1]);
}
}
...
The code above is giving the error: Undefined variable: field. From the Log output I get this:
[2017-06-21 06:32:25] local.INFO: BaseModel::filtered->organisation.name
I've tried calling the field variable by $this->field as well, also fails. I also get the same error if i reference the $col parameter directly. Yet both $search and $sort are fine.
$data = $data->where(function ($query) use ($search, $field) { //Add extra parameters inside your use same as search.
return $query->where($field,'like','%'.$search.'%') ;
});
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;
}
}
So I have the following XML chain:
$xml->assessment->outcomes_processing->outcomes->decvar->attributes()->cutvalue
XML example
In Some XML-files $xml->assessment->outcomes_processing->outcomes->... does exist. But here only $xml->assessment exist.
<questestinterop>
<assessment ident="nedolat78356769204914" title="welkom woordenschat 4">
<qtimetadata>
<qtimetadatafield>
<fieldlabel>qmd_assessmenttype</fieldlabel>
<fieldentry>Assessment</fieldentry>
</qtimetadatafield>
</qtimetadata>
<section ident="nedolat78356769204915" title="Woordenschat">
<selection_ordering>
<selection/>
<order order_type="Sequential"/>
</selection_ordering>
<item ident="QTIEDIT:FIB:34932158" title="Oefening 1">
...
</item>
</section>
</assessment>
</questestinterop>
At the moment I am receiving the error: "Trying to get property of non-object". Which is logic because the node from outcomes doesn't exist.
So I tried a solution with isset() which obviously isn't working either.
isset($xml->assessment->outcomes_processing->outcomes->decvar->attributes()->cutvalue) ? ... : null
This gives me the same error. Because the node outcomes doesn't exist, so he throws me the error immediately. The solution could be for checking each node individually with isset(), of course with a function because otherwise I have a lot of checking to do...
This is my function, which is failed to work because the string '->' could not be processed as php code:
// xml: xml structure form SimpleXML
// chain: assessment->outcomes_processing->outcomes->decvar->attributes()->cutvalue
function checkIfXMLChainExists($xml, $chain) {
$xmlChain = '';
$i = 0;
$nodes = explode('->', $chain);
$numItems = count($nodes);
// experimenting with eval() to treat '->' as ->; failed to work
$a = '$xml->assessment->outcomes_processing';
$t = eval($a);
echo $t;
print_r($t);
foreach ($nodes as $node) {
$xmlChain .= '->' . $node;
if (isset($xml->$xmlChain)) { // Node exists
if ($i+1 == $numItems) {
return $xml->$xmlChain;
}
} else { // Node does not exists
return 'does not exist';
}
$i++;
}
Does anyone has some ideas because I don't have any inspiration at the moment :(
Thanks in advance
Returns the data referenced by the chain, or NULL if it doesn't exist.
function getDataIfExists () {
// We accept an unknown number of arguments
$args = func_get_args();
if (!count($args)) {
trigger_error('getDataIfExists() expects a minimum of 1 argument', E_USER_WARNING);
return NULL;
}
// The object we are working with
$baseObj = array_shift($args);
// Check it actually is an object
if (!is_object($baseObj)) {
trigger_error('getDataIfExists(): first argument must be an object', E_USER_WARNING);
return NULL;
}
// Loop subsequent arguments, check they are valid and get their value(s)
foreach ($args as $arg) {
$arg = (string) $arg;
if (substr($arg, -2) == '()') { // method
$arg = substr($arg, 0, -2);
if (!method_exists($baseObj, $arg)) return NULL;
$baseObj = $baseObj->$arg();
} else { // property
if (!isset($baseObj->$arg)) return NULL;
$baseObj = $baseObj->$arg;
}
}
// If we get here $baseObj will contain the item referenced by the supplied chain
return $baseObj;
}
// Call it like this:
$subObj = getDataIfExists($xml, 'assessment', 'outcomes_processing', 'outcomes', 'decvar', 'attributes()', 'cutvalue');
I have strict error reporting. I have to use isset and it make me to write long, repetitive chains of variables in PHP. I have sometimes to write code like this:
if (isset($my_object->an_array[$a_variable])):
$other_variable = $my_object->an_array[$a_variable];
else:
$other_variable = false;
endif;
or
if (isset($my_object->an_array[$a_variable])):
return $my_object->an_array[$a_variable];
endif;
Sometimes it is longer and more complicated. It isn't readable and take too much time to type. I'd like to get rid of it.
The question
Is there a way to write $my_object->an_array[$a_variable] only once?
You can write functions to encapsulate repetitive code:
function get_variable(array $array, $variable_name, $default_value=FALSE){
if( isset($array[$variable_name]) ){
return $array[$variable_name];
}else{
return $default_value;
}
}
Tweak to your needs.
In the end I have found two solutions.
I. There is operator # in PHP. It is very dangerous, tough.
http://www.php.net/manual/en/language.operators.errorcontrol.php
However, it is acceptable in my situation.
This is not a fatal error.
The value of undefined variable is defined as null. I'm fine with testing for this or using implicit conversions.
I can use $php_errormsg in extreme situations.
The code example:
$tmp = $false_object->property->property; #Throw notice
$tmp = $false_array['a_field']['a_field']; #Throw notice
$tmp = #$false_object->property->property; #Quiet
$tmp = #$false_array['a_field']['a_field']; #Quiet
echo $php_errormsg; #I can print that notice
The downside is I don't receive information about lack of quotes in brackets.
$a = array('e'=>false);
$tmp = $a[e]; #Throw notice
$tmp = #$a[e]; #Quiet
echo $php_errormsg; #This variable still works
II. It is possible to use operator &.
The value of undefined variable will be NULL too.
The $php_errormsg variable doesn't work for undefined variables.
I get notice for lack of quotes in brackets, though.
The code example:
$tmp = $false_object->property->property; #Throw notice
$tmp = $false_array['a_field']['a_field']; #Throw notice
$tmp = &$false_object->property->property; #Quiet
$tmp = &$false_array['a_field']['a_field']; #Quiet
var_dump($tmp); #NULL;
The lack of quotes problem:
$array = array('a_field'=>true);
$tmp = $array[a_field]; #Throw notice
$tmp = #$array[a_field]; #Quiet
$tmp = &$array[a_field]; #Throw notice
function check($var)
{
if(isset[$var])
return $var;
else
return "";
}
Then each time you need to do checking call like:
$other_b = check($b);
I doubt you will get any suggestions that you will consider satisfactory. The best I can suggest is this, and I would add that I consider it quite ugly:
function ifset ($var) {
return is_null($var) ? false : $var;
}
Having defined this function, you can call it like this:
$other_variable = ifset(#$my_object->an_array[$a_variable]);
Note that you need the error suppression operator here, because otherwise you'll get an undefined variable notice if the variable indeed doesn't exist. (The reason why you don't need it for isset() is that isset() is really a special parser token rather than an ordinary function.)
now i get the same problem. i must check it and then get it ,it's so ugrly.
so i write the function like this
function get_val($arr,$key,$default_val=false){
if(!is_array($arr)) return $default_val;
$idx = explode('>>',$key);
$tmp = $arr;
$catched = true;
foreach($idx as $index) {
if(!isset($tmp[$index])){
$catched = false;
break;
}else{
$tmp = $tmp[$index];
}
}
if($catched) $default_val = $tmp;
return $default_val;
}
//for example
$arr = array('k1'=>array('k2'=>array(1,'k22'=>22,'k23'=>array('k3'=>1))));
get_val($arr,'k1>>k2>>k23>>k3');
A method to extract those variables would probably be better in your case, then:
class MyObject
{
private $an_array;
public function __construct()
{
$this->an_array = array();
}
public function get( $key )
{
if(isset($this->an_array[$key]))
return $this->an_array[$key];
return false; //or empty string
}
public function set( $key, $value )
{
$this->an_array[$key] = $value;
}
}
That way, you can do it like this:
$my_object->get($a_variable]);
I use these little helper functions to access properties of (multidimensional) arrays/objects without writing repetitive isset() statements. They might not be the fastest running solution, but they are very comfortable:
// AI(data,1,default) === data[1] or default
function AI( $a, $i, $d=null ){
if( is_array ($a)){ if( array_key_exists( $i, $a )) return $a[ $i ]; return $d; }
if( is_object($a)){ if( property_exists( $a, $i )) return $a -> $i; return $d; }
return $d;
}
// AII(data,1,2,3) === data[1][2][3] or null
function AII( $o ){
$a = func_get_args();
$al = func_num_args();
for( $i=1; $i < $al; $i++ ){
$k = $a[$i];
if( is_array ($o) && array_key_exists($k,$o)) $o =& $o[ $k ];
else if( is_object($o) && property_exists ($o,$k)) $o =& $o -> $k;
else return null; // nothing to access
}
return $o;
}
// AIID(data,1,2,3,default) == data[1][2][3] or default
function AIID( $o ){
$a = func_get_args();
$default = end( $a );
$al = count( $a ) - 1;
for( $i=1; $i < $al; $i++ ){
$k = $a[$i];
if( is_array ($o) && array_key_exists($k,$o)) $o =& $o[ $k ];
else if( is_object($o) && property_exists ($o,$k)) $o =& $o -> $k;
else return $default;
}
return $o;
}
// AAID(data,[1,2,3],default) == data[1][2][3] or default
function AAID( $o, $a, $default = null ){
foreach( $a as $k ){
if( is_array ($o) && array_key_exists($k,$o)) $o =& $o[ $k ];
else if( is_object($o) && property_exists ($o,$k)) $o =& $o -> $k;
else return $default;
}
return $o;
}
I'm looking for a nice way of doing the magicFunction():
$indexes = array(1, 3, 0);
$multiDimensionalArray = array(
'0',
array('1-0','1-1','1-2',array('2-0','2-1','2-2')),
array('1-4','1-5','1-6')
);
$result = magicFunction($indexes, $multiDimensionalArray);
// $result == '2-0', like if we did $result = $multiDimensionalArray[1][3][0];
Thanks.
You can solve this recursively.
$indexes = array(1, 3, 0);
$multiDimensionalArray = array(
'0',
array('1-0','1-1','1-2',array('2-0','2-1','2-2')),
array('1-4','1-5','1-6')
);
$result = magicFunction($indexes, $multiDimensionalArray);
function magicFunction($indices, $array) {
// Only a single index is left
if(count($indices) == 1) {
return $array[$indices[0]];
} else if(is_array($indices)) {
$index = array_shift($indices);
return magicFunction($indices, $array[$index]);
} else {
return false; // error
}
}
print $result;
This function will go down the $multiDimensionalArray as long as there are indices available and then return the last value accesses by the index. You will need to add some error handling though, e.g. what happens if you call the function with $indexes = array(1,2,3,4);?
This is a recursive version. Will return null if it cannot find a value with the given index route.
function magicFunction($indexes, $array) {
if (count($indexes) == 1) {
return isset($array[$indexes[0]]) ? $array[$indexes[0]] : null;
} else {
$index=array_shift($indexes);
return isset($array[$index]) ? magicFunction($indexes, $array[$index]) : null;
}
}
You can just step trough based on your keys (no need to do any recursion, just a simple foreach):
$result = &$multiDimensionalArray;
foreach($indexes as $index)
{
if (!isset($result[$index]))
break; # Undefined index error
$result = &$result[$index];
}
If you put it inside a function, then it won't keep the reference if you don't want to. Demo.
I think something like this should do the trick for you.
function magicFuntion($indexes, $marray)
{
if(!is_array($indexes) || count($indexes) == 0 || !is_array($marray))
return FALSE;
$val = '';
$tmp_arr = $marray;
foreach($i in $indexes) {
if(!is_int($i) || !is_array($tmp_arr))
return FALSE;
$val = $tmp_arr[$i];
$tmp_arr = $tmp_arr[$i];
}
return $val;
}
Try this :P
function magicFunction ($indexes,$mdArr){
if(is_array($mdArr[$indexes[0]] && $indexes)){
magicFunction (array_slice($indexes,1),$mdArr[$indexes[0]]);
}
else {
return $mdArr[$indexes[0]];
}
}
My own attempt ; found it simpler by not doing it recursively, finally.
function magicFunction($arrayIndexes, $arrayData)
{
if (!is_array($arrayData))
throw new Exception("Parameter 'arrayData' should be an array");
if (!is_array($arrayIndexes))
throw new Exception("Parameter 'arrayIndexes' should be an array");
foreach($arrayIndexes as $index)
{
if (!isset($arrayData[$index]))
throw new Exception("Could not find value in multidimensional array with indexes '".implode(', ', $arrayIndexes)."'");
$arrayData = $arrayData[$index];
}
return $arrayData;
}
Exceptions may be somewhat "violent" here, but at least you can know exactly what's going on when necessary.
Maybe, for sensitive hearts, a third $defaultValue optional parameter could allow to provide a fallback value if one of the indexes isn't found.