Scope of PHP function

2019-02-23 14:59发布

问题:

I have a file that corrals my re-usable functions into one file (functions.php). It's include_once()'d on every page that needs it. I'm getting an error when my custom functions are trying to access a MySQL connection outside their own scope. The source is a bit like this:

<?php
    // functions.php
    $connect = mysql_connect("localhost", "user", "pass") or die("MySQL said: ".mysql_error());
    mysql_select_db("database", $connect) or die("MySQL said: ".mysql_error()); // no error

    /* ... */

    function getmotd($user) {           
        $query = "SELECT cid FROM `users`
        WHERE id = ".$user;
        $query = mysql_query($query, $connect); // error occurs here, $connect is not a valid MySQL link-resource
        /* ... */
    }
?>

Why can't my function access variables declared above it's scope? I can get a successful connection by reproducing $connect's declaration within the function.

Any insight into how I can work around this or what I'm doing wrong here?

回答1:

Use the global keyword.

Example

function getmotd($user) {  
     global $connect;
    $query = "SELECT cid FROM `users`
    WHERE id = ".$user;
    $query = mysql_query($query, $connect); // error occurs here, $connect is not a valid MySQL link-resource
    /* ... */
}

You can also do it like this

function getmotd($user) {  
    $query = "SELECT cid FROM `users`
    WHERE id = ".$user;
    $query = mysql_query($query, $GLOBALS['connect']); // error occurs here, $connect is not a valid MySQL link-resource
    /* ... */
}

If you want to make re-usable codes, you'd probably be better off with OOP. Create a class for the database, and add some properties for the database info, and access them from the functions by using the this keyword.



回答2:

You can't access $connect because it is outside the scope of the function; that is, PHP can only see the variables within the function when it's inside it. You could use the global keyword to let PHP know the variable is outside the function's scope as Kemal suggests, but I think a better course of action is to pass the connection into the function. This will give you better encapsulation. If you learn to write your functions (and later classes) with passing in the resources and data you need (a practice known as "dependency injection"), you'll find you have cleaner and more maintainable code. Here's the example:

function getmotd($db, $user) {
    $query = "SELECT cid FROM users WHERE id = " . (int)$user;
    $result = mysql_query($query, $db);
    /.../
}

$connect = mysql_connect(...);
mysql_select_db(...);
$motd = getmotd($connect, $user);

Hope this helps.