-1

I need help trying to call a class function within another class. Here's my setup:

db.php

class db
{
function connect(){
//db connection code here
}
function query($sql){
//perform query and return results
}
}//end db class

main.php

class main
{
function test(){
$sql = "select * from user";
$result = $db->query($sql);//does not work
}
}//end class

index.php

require_once './db.php';
$db=new database;
$db->connect();
//so far so good
require_once './main.php';
$main=new main;
//rest of the code here

The problem is that on index.php I can run $db->query($sql) without any problems, but I can't seem to run them inside the main class, more specifically inside the test function. So if I call $main->test() from index.php I get this error:

Fatal error: Call to a member function query() on a non-object in /path/to/file
tereško
  • 58,060
  • 25
  • 98
  • 150
user962449
  • 3,743
  • 9
  • 38
  • 53

4 Answers4

3

Unlike C global variables in PHP are not in the visibility scope of functions/methods, see http://docs.php.net/language.variables.scope
To access global variables you must either import them into the function's scope via global $var or acccess them through the superglobal $_GLOBAL

But instead of using global variables you might be interested in dependency injection, e.g. (one of many possible ways to implement di):

<?php
$db = new db;
$db->connect();
$main = new main($db);
$result = $main->test();

class db
{
    function connect(){
        //db connection code here
    }
    function query($sql){
        //perform query and return results
    }
}


class main
{
    protected $db;
    public function __construct($db) {
        $this->db = $db;
    }

    public function test(){
        $sql = "select * from user";
        return $this->db->query($sql);
    }
}
Gordon
  • 312,688
  • 75
  • 539
  • 559
VolkerK
  • 95,432
  • 20
  • 163
  • 226
  • @Gordon: Why didn't you like the registry/array thing and narrowed it down to $db ? – VolkerK Sep 24 '11 at 14:25
  • see my commit message. To do DI you do not need a Registry. You just inject the Dependency. Under the premise that the simplest example is the best example, I felt it would be easier to illustrate the point without adding a new concept to the answer (Registry), especially since Registries violate Law of Demeter and are somewhat controversial regarding DI because you cannot see from the method signature what the consuming class needs in order to run. Registries are kinda like globals in their own scope. Feel free to rollback though. – Gordon Sep 24 '11 at 14:46
1

I would add a static getInstance() method into the Db class. Then cou can call Db::getInstance()->query(...) from every scope. You can read more on this pattern on Wikipedia.

str
  • 42,689
  • 17
  • 109
  • 127
  • Adding a static method `getInstance` doesnt make a class a Singleton. You need additional boilderplate code for that. [And Singletons should be avoided anyway](http://stackoverflow.com/questions/4595964/who-needs-singletons/4596323#4596323) – Gordon Sep 24 '11 at 10:58
0

Just put:

global $db;

in your test() function.

But if you do this also make sure you check that $db exists and is what you think it is before you use it this way.

Anonymous
  • 3,334
  • 3
  • 35
  • 50
  • What about if I want to use $db in more than one function inside my main class? Can I add global to each funtion? Or is there a simplier way? Thanks for your help! I've been up all night trying to figure this out, it's almost 3am here > – user962449 Sep 24 '11 at 09:44
  • If globals are the answer, you're asking the wrong questions. Related: http://stackoverflow.com/questions/5859679/why-is-global-object-name-discouraged/5859835#5859835 – Erik Sep 24 '11 at 09:47
  • How can I refrence $db using __construct? Or is there a better way? – user962449 Sep 24 '11 at 09:57
  • @user962449 see the upvoted answer. Dependency injection. Create your DB object and pass it to the constructor of the object where you wish to use it. – Erik Sep 24 '11 at 10:02
  • Just for the record, this works and is quick. He didn't ask for the best solution, just something to get the code working, and this does that. – Anonymous Sep 24 '11 at 10:20
  • 1
    @doug it may work and be quick, but so does SQL that leaves people open to injection attacks. As a general policy giving solutions which are generally considered A Bad Idea is frowned upon. – Erik Sep 26 '11 at 15:01
0

I guess you should be using

$db = new db;

because $db is not defined in your main class.

Salman
  • 115
  • 1
  • 2
  • 8