在类中使用全局变量 [英] Use global variables in a class

查看:246
本文介绍了在类中使用全局变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建一个分页类,并使用类外的变量。



但它给我一个致命的错误调用成员函数查询()on a non-object。



这是索引文件:

  $ db = new DB_MySQL(localhost,root,,test); //连接到数据库
include_once(pagi.php);

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

这是pagi.php文件:

  class pagi {

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

}

是否可以使用此变量

解决方案

正确的方法来解决这个问题将数据库句柄注入到其他类中(依赖注入):

  $ db = new DB_MySQL(localhost,root,,test); //连接到数据库
include_once(pagi.php);

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

class Paginator
{
protected $ db;

//当可用时可能更好地使用一些通用的数据库接口作为typehint
public function __construct(DB_MySQL $ db)
{
$ this-> db = $ db;
}

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

}

通过将数据库类的实例注入到使用它的方法中:

  $ db = new DB_MySQL(localhost root,,test); //连接到数据库
include_once(pagi.php);

$ pagination = new Paginator();
$ records = $ pagination-> get_records(SELECT,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);
}

}

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



已将您的类别从 pagi 重新命名为 Paginator 。 Paginator是一个更好的名字IMHO的类,因为它是清楚的其他人(re)查看您的代码。



我做的另一件事是更改为查询以显示您选择的字段,而不是使用通配符

code> * 。这是因为同样的原因,我改变了类名。



更新 p>

因为从我的回答开始讨论为什么我会去依赖注入路由而不是声明对象 global 我想澄清为什么我会去使用依赖注入的路线,而不是使用全局关键字。这是因为当你有如下的方法:

  function get_records($ q){
global $ db ;

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

当你在上面使用上述方法时, /该方法使用 $ db 依赖项。因此它是一个隐藏的依赖。上面的错误的另一个原因是因为你将 $ db 实例(因此 DB_MySQL )紧密耦合到该方法/类。如果你需要两个在某个点使用2数据库。现在,您必须通过所有代码将全局$ db 更改为全局$ db2 。你应该永远不需要改变你的代码只是切换到另一个数据库。这些是你不应该做的相同的原因:

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

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

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



有些人可能认为Singleton模式是访问数据库对象的正确方法,但是应该清楚(通过阅读所有上述内容),单例基本上只是另一种使事情 global 。它可能看起来不同,但它具有完全相同的特性,因此与全局相同的问题。


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

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:

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?

解决方案

The correct way to solve this would be to inject the database handle 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 injection 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 in the situation. If only one method needs an instance of the database class 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 pagi to Paginator. Paginator is a better name IMHO for the class because it is clear for other people (re)viewing your code. Also not that I have made the first letter uppercase.

Another thing I have done is changed to query to show the fields you are selecting instead of using the "wildcard" *. This is because of 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.

Update

Because the fact that from my answer sprung a discussion about why I would go the dependency injection route instead of declaring the object global I would like to clarify why I would go for the route of dependency injection instead of using a global keyword. It is because when you have a method like the following:

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 / the method uses the $db dependency. Hence it is a hidden dependency. Another reason why the above is bad is because you have tightly coupled the $db instance (thus the DB_MySQL) class to that method / class. What if you need two use 2 database at some point. Now you would have to go through all code to change global $db to global $db2. You should never need to change your code just to switch to another database. These are the same reason why you shouldn't do:

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 it tightly coupled the DB_MySQL class to the method / class. Because of this it is also impossible now properly unit test the Paginator class. Because instead of testing only the unit (the Paginator class) you are also testing the DB_MySQL class 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 the dependencies) it will also make sure your tests will finish fast.

Some people may think the Singleton pattern is the correct way to get access to a database object, but as it should be clear by (by 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.

这篇关于在类中使用全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆