Avoiding `Undefined Property` in PHP when using `isset()` in a callback?

1.9k views Asked by At

I have written a validation trait for my model classes, as well as an error reporting library which formats and returns a JSON object of errors, warnings, etc.

In my validation trait, I have this method...

function hasValue($value)
{
  return (isset($value) && !(trim($value) === ''));
}

PHP will throw a warming if I just try to use !(trim($value) in a conditional that tells me the variable is undefined. So, you have to do this...

if (isset($value) && !(trim($value) === ''))
  //Do Something

I created this method to consolidate a very common task requiring two methods into a single method, but I am getting the same warning as if I had used the trim() method alone.

Is there a way to do this without turning off warnings?

EDIT

There seems to be some confusion. I need this to work for variables, and object properties. I'm attempting to turn this...

if (empty($obj->email) && $this->validateEmail($obj->email))
  //Do Something

Into this...

if ($this->validateEmail($obj->email))
  //Do Something

By having my hasValue() method to call on will, and inside the validateEmail() method.

2

There are 2 answers

1
Xorifelse On

The problem you're having is that your function hasValue() evaluates both statements isset($value) and !(trim($value) === '') as one

Instead you should evaluate !(trim($value) === '') if isset($value) equals true. This is done by removing the outer parenthesis.

function hasValue($value){
  return isset($value) && !(trim($value) === '');
  # if this ^^^^ is false this ^^^^ is never executed and no warning generated.
}

That would resolve the warning, however hasValue() sounds more like a function to check if any variable has a value, perhaps do this instead:

function hasValue($value){
  return isset($value) && !empty($value) || is_string($value) && !empty(trim($value));
}

var_dump(hasValue(null));  // false
var_dump(hasValue(true));  // true
var_dump(hasValue(false)); // false
var_dump(hasValue([]));    // false
var_dump(hasValue(''));    // false
var_dump(hasValue(' '));   // false
var_dump(hasValue('a'));   // true

interface validateInterface{
  public static function validateEmail($email);
  public static function validateEmailObj();
}

trait validateTrait{
  static function validateEmail($email){
    return filter_var($email, FILTER_VALIDATE_EMAIL); 
  }
  function validateEmailObj(){
    return filter_var($this->email, FILTER_VALIDATE_EMAIL); 
  }
}

# Implementing an interface is not required, but recommended as traits are easily overwritten.
class MyClass implements validateInterface{
  use validateTrait;

  public $email;

  function __construct($email){
    if(self::validateEmail($email)){
      echo 'works statically inside';
    }

    $this->email = $email;
  }
}

$mail = '[email protected]';

if(MyClass::validateEmail($mail)){
  echo 'works statically outside class';
}

if((new MyClass($mail))->validateEmailObj()){
  echo 'works with objects';
}

For a longer list of values what isset and empty does see here

3
Barmar On

This might be a reasonable place to use the @ modifier to suppress warnings.

if (@trim($value) != '')

If $value is undefined, it will be converted to an empty string. Using @ suppresses the warning message when this happens.