【问题标题】:PHP class scopePHP 类范围
【发布时间】:2011-09-05 00:21:42
【问题描述】:

我目前正在构建的应用程序中有几个类,我希望其中一个访问其他的一些成员函数,但我似乎做不到。

第一类叫做MySQLDB:

class MySQLDB{
public $connection;

function __construct(){
//connects to database
}

function login($username, $password){
//queries database...
}
}

然后我有一个类叫Session:

class Session{
//variables
//constructor

function processlogin($username, $password){
$database->login($username, $password);
}

然后我有两个类声明:

$database = new MySQLDB();
$session = new Session();

无论我将这些与类相关的语句放在哪里,我仍然会遇到相同的错误:

PHP Notice:  Undefined variable: database in C:\inetpub\wwwroot\cmu\include\session.php on line 52
PHP Fatal error:  Call to a member function login() on a non-object in C:\inetpub\wwwroot\cmu\include\session.php on line 52

我看到了一些建议,建议将新数据库对象放在 Session 类声明中,但我想避免这样做,因为我在代码中的其他几个地方使用了数据库类,我不想打开多个与数据库的连接。

【问题讨论】:

    标签: php oop class scope


    【解决方案1】:

    由于您想访问全局设置的变量,您可以使用global 访问它:

    function processlogin($username, $password){
        global $database;
        $database->login($username, $password);
    }
    

    或将变量用作构造函数的参数并记住类Session中的数据库对象引用:

    class Session{
    
        private $database;
    
        function __construct($database){
            $this->$database = $database;
        }
    
        function processlogin($username, $password){
            $this->database->login($username, $password);
        }
    
    }
    

    然后你打电话:

    $database = new MySQLDB();
    $session = new Session($database);
    

    这个就派上用场了,如果你在后面使用更多的函数,那也需要访问数据库对象。

    【讨论】:

    • 谢谢我刚刚使用了global $database 语句,它现在工作得很好。我计划在有机会时尝试第二种方法,但我想与您核实以确保它引用了该对象并且不会创建重复项。
    • 我的最新项目需要类似的东西,我意识到我正在为同一件事运行大约 10 个数据库实例。如果MySQLDB 实例需要同时被其他类使用,这可能是个问题,因为Session 实例中的$database 对象不会引用同一个实例。因此,如果您从另一个地方更改对象,那么您的班级将看不到该修改。说你想做这样的事情:$database->setEncoding('utf-8');;那么你将不得不为你的会话数据库做同样的事情:$session->database->setEncoding('utf-8')
    • 在类中使用global。它完全破坏了你的类的封装。 仅在此答案中使用方法 2
    【解决方案2】:

    您可以在Session 构造函数中传递对MySQLDB 实例的引用。

    class Session{
        public $db;
    
        function __construct(&$db=null){
            if($db == null)
                $this->db = new MySQLDB();
            else
                $this->db = $db;
        }
        // ....
    }
    
    $database = new MySQLDB();
    $session = new Session($database);
    

    【讨论】:

      【解决方案3】:

      您正在创建两个全局变量。如果你正在做这样的事情,你需要用“global”关键字声明你想在函数中使用的变量:

      function processlogin($username, $password){
      global $database;
      $database->login($username, $password);
      }
      

      尽管这会起作用,但我强烈建议阅读有关依赖注入机制的信息,在该机制中,您可以将 $database 变量作为参数传递给 processlogin() 方法,或者在构造函数/设置器中将其设置为该类的私有成员。这样,数据库连接将是可互换的,您的代码将获得更大的灵活性。

      【讨论】:

        【解决方案4】:

        $database 没有在processlogin 中定义,也没有作为参数传递,因此函数无法访问它。

        你可以将它作为构造函数参数传递给Session:

        class Session {
            private $db;
        
            public function __construct($database) {
                $this->db = $database;
        
            public function processlogin($username, $password){
                $this->$db->login($username, $password);
            }
        }
        
        $database = new MySQLDB();
        $session = new Session($database);
        

        【讨论】:

        • 为什么不创建一个有子类的父类,然后调用父类或子类?
        • @Gerald:你的意思是Session 应该是MySQLDB 的孩子?继承表示 is-a 关系,但 Session 不是 MySQLDB。一个会话使用一个数据库,这就是组合的用途。它只是在语义上更有意义,但当然你可以做任何你想做的事;)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-08
        • 2011-05-21
        • 2012-06-25
        • 2018-08-13
        • 2013-07-28
        • 1970-01-01
        • 2023-03-30
        相关资源
        最近更新 更多