php 在类中使用全局变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11923272/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 02:27:37  来源:igfitidea点击:

Use global variables in a class

phpsqlclassoop

提问by Marcoo

I'm trying to create a pagination class and use a variable from outside the class.

我正在尝试创建一个分页类并使用类外部的变量。

But it's giving me the fatal error "Call to a member function query() on a non-object".

但它给了我致命错误“调用非对象上的成员函数 query()”。

This is the index file:

这是索引文件:

$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");

$pagination = new pagi();
$records = $pagination->get_records("SELECT * FROM `table`");

And this is the pagi.php file:

这是 pagi.php 文件:

class pagi {

    public function get_records($q) {
        $x = $db->query($q);
        return $db->fetch($x);
    }

}

Is it possible to use this variable from out side of the class inside the class, without creating a new one inside the class?

是否可以在类内部的类外部使用此变量,而无需在类内部创建新变量?

回答by PeeHaa

The correct way to solve this would be to inject the database object into the other class (dependency injection):

解决这个问题的正确方法是将数据库对象注入另一个类(依赖注入):

$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");

$pagination = new Paginator($db);
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`");

class Paginator
{    
    protected $db;

    // Might be better to use some generic db interface as typehint when available
    public function __construct(DB_MySQL $db)
    {
        $this->db = $db;
    }

    public function get_records($q) {
        $x = $this->db->query($q);
        return $this->db->fetch($x);
    }

}

Another way you could solve it is by injecting the instance of the database class into the method that uses it:

另一种解决方法是将数据库类的实例注入到使用它的方法中:

$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");

$pagination = new Paginator();
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`", $db);

class Paginator
{
    public function get_records($q, DB_MySQL $db) {
        $x = $db->query($q);
        return $db->fetch($x);
    }

}

Whichever method you choose depends on the situation. If only one method needs an instance of the database you can just inject it into the method, otherwise I would inject it into the constructor of the class.

您选择哪种方法取决于具体情况。如果只有一个方法需要数据库的实例,您可以将它注入到方法中,否则我会将它注入到类的构造函数中。

Also note that I have renamed your class from pagito Paginator. Paginator is a better name IMHO for the class because it is clear for other people (re)viewing your code. Also note that I have made the first letter uppercase.

另外请注意,我从你的改名类pagiPaginator。Paginator 是一个更好的名字恕我直言,因为其他人(重新)查看您的代码很清楚。另请注意,我将第一个字母设为大写。

Another thing I have done is changed the query to select the fields you are using instead of using the "wildcard" *. This is for the same reason I have changed the classname: People (re)viewing your code will know exactly what fields will be retrieved without checking the database and/or the result.

我所做的另一件事是更改查询以选择您正在使用的字段,而不是使用 "wildcard" *。这与我更改类名的原因相同:(重新)查看您的代码的人将确切知道将检索哪些字段,而无需检查数据库和/或结果。

Update

更新

Because answer gave rise to a discussion regarding why I would go the dependency injection route instead of declaring the object global, I would like to clarify why I would use dependency injection over the globalkeyword: When you have a method like:

因为 answer 引起了关于为什么我会去依赖注入路由而不是声明 object 的讨论global,我想澄清为什么我会在global关键字上使用依赖注入:当你有一个方法时:

function get_records($q) {
    global $db;

    $x = $db->query($q);
    return $db->fetch($x);
}

When you are using the above method somewhere it isn't clear that the class or method uses depends on $db. Hence it is a hidden dependency. Another reason why the above is bad is because you have tightly coupled the $dbinstance (thus the DB_MySQL) class to that method / class. What if you need to use 2 databases at some point. Now you would have to go through all code to change global $dbto global $db2. You should never need to change your code just to switch to another database. For this reason, you should not do:

当您在某处使用上述方法时,不清楚类或方法使用的依赖于$db. 因此它是一个隐藏的依赖。上面不好的另一个原因是因为您将$db实例(因此DB_MySQL)类与该方法/类紧密耦合。如果您在某个时候需要使用 2 个数据库怎么办。现在,您必须遍历所有代码才能更改global $dbglobal $db2. 您永远不需要为了切换到另一个数据库而更改代码。出于这个原因,你不应该这样做:

function get_records($q) {
    $db = new DB_MySQL("localhost", "root", "", "test");

    $x = $db->query($q);
    return $db->fetch($x);
}

Again, this is a hidden dependency, and tightly couples the DB_MySQLclass to the method / class. Because of this it is also impossible to properly unit test the Paginatorclass. Instead of testing only the unit (the Paginatorclass) you are also testing the DB_MySQLclass at the same time. And what if you have multiple tightly coupled dependencies? Now you are suddenly testing several classes with your so called unit tests. So when using dependency injection you can easily switch to another database class, or even a mocked one for testing purposes. Besides the benefit of testing only one unit (you don't have to worry about getting wrong results because of dependencies) it will also make sure your tests will finish fast.

同样,这是一个隐藏的依赖项,并将DB_MySQL类与方法/类紧密耦合。因此,也不可能对Paginator类进行正确的单元测试。您不仅要测试单元(Paginator类),还要同时测试DB_MySQL类。如果您有多个紧密耦合的依赖项怎么办?现在您突然用所谓的单元测试测试了几个类。因此,在使用依赖注入时,您可以轻松切换到另一个数据库类,甚至是用于测试目的的模拟类。除了只测试一个单元的好处(你不必担心因为依赖而得到错误的结果),它还可以确保你的测试快速完成。

Some people may think the Singleton pattern is the correct way to get access to a database object, but it should be clear, having read all of the above, a singleton is basically just another way of making things global. It might look different, but it has the exact same characteristics and hence the same problems as global.

有些人可能认为单例模式是访问数据库对象的正确方法,但应该清楚,在阅读了上述所有内容后,单例模式基本上只是另一种制作方法global。它可能看起来不同,但它具有完全相同的特征,因此与global.

回答by Jonathan Kuhn

Although I do agree that the dependency model is nice, for the database, I personally use a static connection that is available to all instances of the database class and the create instances to query whenever I need one. Here is an example:

尽管我确实同意依赖模型很好,但对于数据库,我个人使用静态连接,该连接可用于数据库类的所有实例,并在需要时创建实例进行查询。下面是一个例子:

<?php
//define a database class
class DB {
    //the static connection.
    //This is available to all instances of the class as the same connection.
    private static $_conn;

    //store the result available to all methods
    private $result;
    //store the last query available to all methods
    private $lastQuery;

    //static connection function. connects to the database and stores that connection statically.       
    public static function connect($host, $user, $pass, $db){
        self::$_conn = mysqli_connect($host, $user, $pass, $db);
    }

    //standard function for doing queries. uses the static connnection property.
    public function query($query){
        $this->lastQuery = $query;
        $this->result = mysqli_query(self::$_conn, $query);
        //process result, return expected output.
    }
}

//create connection to the database, this connection will be used in all instances of DB class
DB::connect('local', 'DB_USER', 'DB_PASS');

//create instance to query
$test = new DB;
//do query
$test->query("SELECT * FROM TABLE");

//test function
function foo(){
    //create instance to use in this function
    $bar = new DB;
    //do query
    $bar->query("SELECT * FROM OTHER_TABLE");
    //return results
    return $bar->fetchArray();
}

That way I can create all the instances I want of DB within any function, method...etc and use that local instance of the class to do all my queries. All instances use the same connection.

这样我就可以在任何函数、方法等中创建我想要的 DB 的所有实例,并使用该类的本地实例来完成我的所有查询。所有实例都使用相同的连接。

One thing to note though is that this only allows for one connection to the database per defined class but I only use one so this isn't an issue for me.

不过要注意的一件事是,这仅允许每个定义的类与数据库建立一个连接,但我只使用一个,所以这对我来说不是问题。

回答by Marcel Hebing

you could add the db-connection ($db) to the call of the get_recordsmethod:

您可以将 db-connection ( $db)添加到get_records方法的调用中:

Here are only the relevant lines of code:

这里只是相关的代码行:

First file:

第一个文件:

$records = $pagination->get_records("SELECT * FROM `table`", $db);

Second file:

第二个文件:

public function get_records($q, $db) {

回答by Colin Kroll

The other answers thus far are definitely preferable to using a global since that will ruin your encapsulation (eg you'd need to have that object defined prior to calling that method).

到目前为止,其他答案绝对比使用全局更可取,因为这会破坏您的封装(例如,您需要在调用该方法之前定义该对象)。

It's much better to enforce that in the method signature or not use a class.

在方法签名中强制执行或不使用类要好得多。