Chris G.
Chris G.

Reputation: 3981

PHP script structure and scope to avoid unnecessary function arguments

Lets say you have an program like this:

$info = array(
    'username'=>'jeff',
    'password'=>'kay'
);

function authenticate($user, $pass) {
    if($user == $info['username'] && $pass == $info['password']) {
        return true;
    }
    return false;
}

This code won't work because the $info array isn't in authenticate()'s scope. You would have to pass $info as a parameter of authenticate() like so:

function authenticate($info, $user, $pass) { // ... }

This feels wrong to me.

I could certainly add global $info; inside of authenticate but that feels even more wrong. What is best practice for structuring a PHP program to avoid scope issues like this? You don't see functions requiring you to pass in the 'global' object in modern code it seems like. How do I avoid unnecessary function arguments?

Upvotes: 0

Views: 163

Answers (6)

igorw
igorw

Reputation: 28269

Most people do not notice, but this is actually a very good question.

Many other languages (especially functional ones) have lexical scope. With PHP 5.3 lambdas you get that capability, but only within lambdas. Let me show you what I mean:

$info = array(
    'username'=>'jeff',
    'password'=>'kay'
);

$authenticate = function ($user, $pass) use ($info) {
    if ($user == $info['username'] && $pass == $info['password']) {
        return true;
    }
    return false;
}

if ($authenticate($_POST['username'], $_POST['password'])) {
    // use authenticated
}

With the use you can import variables from the outer scope, but it only works for anonymous functions. It really depends on what kind of style and framework you're coding in/with.

If you don't want to define these inline (since you must assign them to variables, which is not so nice), I'd suggest you go with your instincts, so pass $info into authenticate or make $info an instance variable of the class that authenticate belongs to.

Upvotes: 2

Manos Dilaverakis
Manos Dilaverakis

Reputation: 5869

Edit in reply to comment:

Assuming the 'global' object is an actual object (as in an instantiation of a class) then you need only provide it with a static function that returns the necessary data. Said function will be accessible from anywhere including inside your authentication function.

Upvotes: 0

afuzzyllama
afuzzyllama

Reputation: 6548

Usually login information isn't hardcoded into a script like that, so this is a rather difficult example to expand on.

If you store your information in a DB or a file, then you would just reference that data store in your function and wouldn't have a need for a global variable like that.


If you are dead set on this way, this is something you could do:

function authenticate($user, $pass) {
    if(checkUser($user, $pass)) {
        // I am assuming you'll do more here than just return true   
        return true;
    }
    else {
        return false;
    }
}

function checkUser($user, $pass) {
    $info = array(
        'username'=>'jeff',
        'password'=>'kay'
    );

    if($user == $info['username'] && $pass == $info['password']){
        return true;
    }
    else {
        return false;
    }
}

This way if you ever decide to change your data store or check user code, as long as it returns the proper boolean to authenticate, you'll be fine. Hurray abstraction!

Upvotes: 0

DaveRandom
DaveRandom

Reputation: 88697

It really depends on exactly where your data is coming from.

Given the above example:

  • If your data is stored in a database, retrieve the data from the database from within the scope of the function, rather than storing it in memory.
  • If you data is stored in a hard-coded array, it should probably be in another file. Then you can just include() that file within the function, and $info will be in the scope of the function.
  • If your data is in a hard-coded array that for some odd reason has to be stored in the main file, it either needs to be defined within the function or you would have to pass it in as an argument, or explicitly fetch the data into the scope of the function (using global, $GLOBALS et al).

I would say that the real question you should be asking (of yourself) is:

"How can I optimise the way in which I store and retrieve my data to avoid scoping problems?"

Upvotes: 0

N.B.
N.B.

Reputation: 14091

So out of two possible ways of injecting a variable into scope, both feel wrong to you? That makes no sense.

What's the best way of structuring stuff? The simplest one - if you know number of parameters you need and what type of parameters you need - send those parameters to the function.

Your example code was ok, there's nothing wrong with it (save of course, $info not being passed).

Don't reinvent hot water.

Upvotes: 0

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324800

In this situation, just not using a function would be better. For instance, where you would have:

if( authenticate($user, $pass, $info))

Try:

if( Array("username"=>$user,"password"=>$pass) == $info)

However, as a more general thing, I prefer to pass function parameters where needed. I also like using associative arrays, like you have $info there, as much as possible to have lots of data in few parameters.

Upvotes: 0

Related Questions