0

I am having trouble using a variable generated in one function, as a variable in a second function.

The Problem:

I get Notice: Undefined variable: parameter in the validate function, on the line:

$this->$methodName($item,$value,$parameter) OR $valid=false;

When the function call for splitRulesAndParameters is simply replaced with the code within the function, the problem goes away.

The Scenario:

The following two functions are both within the Validator class, the first, validate, makes use of the second, splitRulesAndParameters

Here is the validate function:

public function validate($data, $rules)
{
    $valid= true;

    foreach($rules as $item=>$ruleSet)
    {
        $ruleSetArray=explode('|',$ruleSet);

        foreach($ruleSetArray as $rule)
        {
            $this->splitRulesAndParameters($rule);
            
            $methodName='validate'.ucfirst($rule);
            $value = isset($data[$item]) ? $data[$item] : NULL;
            
            if(method_exists($this, $methodName))
            {
                $this->$methodName($item,$value,$parameter) OR $valid=false;
            }
        }
    }

    return $valid;
}

And here is the splitRulesAndParameters function

public function splitRulesAndParameters($rule)
{
    $position = strpos($rule, ':');
    if($position !==false)
    {
        $parameter = substr($rule,$position + 1);
        $rule = substr($rule,0,$position);
    }
    else
    {
        $parameter='';
    }
}
3
  • Makes sense: $parameter is never declared... PHP will create a new variable for you (and initialize it to null), but it'll (rightfully) issue a notice Commented Sep 15, 2014 at 9:42
  • Modify your splitRulesAndParameters() to return an array of $rule and $parameter, and use the values from that array in the call to $this->$methodName($item,$value,$parameter).... or use object properties for $this->rule and $this->parameter.... or even refactor to use a dedicated Rule class Commented Sep 15, 2014 at 9:43
  • Please see this recent post stackoverflow.com/questions/25842231/… and my comment on the post Commented Sep 15, 2014 at 9:43

3 Answers 3

1

Seeing as the problem goes away if you "inline" the code in splitRulesAndParameters, I suspect the $parameters variable is used in that method. If so, simply have that method return the value of this variable, and assign it to a variable local to the validate method you've posted here:

$parameters = $this->splitRulesAndParameters($rule);

After adding this to the splitRulsAndParameters method:

return $parameters;

The method itself also modifies the $rule value. Again: this $rule variable is local to each method. It may have the same name, but the value is a copy. Any changes you make to $rule in splitRulesAndParameters is not reflected by $rule in your validate method. If I were you, I'd write:

public function splitRulesAndParameters($rule)
{
    $position = strpos($rule, ':');
    if($position !==false)
    {
        return array(
            'parameter' => substr($rule, $position+1),
            'rule'      => substr($rule, 0, $position)
        );
    }
    return array(
        'parameter' => null,//no param == null, IMO, change to '' if you want
        'rule'      => $rule
    );
}

Then, to change the variables in validate:

$split = $this->splitRulesAndParameters($rule);
$rule = $split['rule'];
$parameter = $split['parameter'];

That ought to do it.

Side-note:
You seem to be validating everything that needs validating, even if the first validation failed. If I were you, I'd change this fugly statement:

$this->$methodName($item,$value,$parameter) OR $valid=false;

To a more efficient:

if (!$this->{$methodName}($item, $value, $parameter))
    return false;//if validation fails, return false

That stops any further valiation from being executed: if one value is invalid, then just stop there. To continue is pointless, because the data-set is not entirely valid anyway.

Bonus:
Using a colon to separate the method name, and some parameter(s) does allow you to specify multiple params, too, and it allows you to simplify the splitRulesAndParameters some more:

protected function splitRulesAndParameters($rule)
{
    $all = explode(':', $rule);
    return array(
        'rule'   => array_shift($all),//removes first element in array
        'params' => $all//rest of the array
    );
}

Tweak this a little to better suite your needs

Sign up to request clarification or add additional context in comments.

1 Comment

thanks Elias. that's what I call above and beyond =) You're points on simplifications are much appreciated as well
0

You can't just use a variable from inside a function in another function. You have to return the variable $parameter. Add a return statement to the end of splitRulesAndParameters and store the result in a variable inside validate ($parameter = $this->spli...).

2 Comments

You've missed the bit where $rule is altered, too: returning $parameter alone doesn't quite cut it here
@EliasVanOotegem Oh, right. But the OP seems to have abandoned the question anyway...
0

You actually have two problems here, because you change the &rule variable inside your function, but you are passing it by reference. So after the fucntion is done the $rule variable is the same as it was before.

The way to solve this in the manner you are doing it right now would be to change the function to:

public function splitRulesAndParameters(&$rule)
{
    $position = strpos($rule, ':');
    if($position !==false)
    {
        $parameter = substr($rule,$position + 1);
        $rule = substr($rule,0,$position);
    }
    else
    {
        $parameter='';
    }
    return $parameter;

}

and change the line

$this->splitRulesAndParameters($rule);

to $parameter = $this->splitRulesAndParameters($rule);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.