datavoredan
datavoredan

Reputation: 3756

Variable scope - php - Using variables from one function in another

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='';
    }
}

Upvotes: 0

Views: 85

Answers (3)

Elias Van Ootegem
Elias Van Ootegem

Reputation: 76408

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

Upvotes: 1

Alfred_P
Alfred_P

Reputation: 792

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);

Upvotes: 0

Butt4cak3
Butt4cak3

Reputation: 2429

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...).

Upvotes: 0

Related Questions