0

I had this error:

Notice: Undefined variable: mysqli in /path/to/component.php on line 24

This was inside this section of code:

class Component {
  public function foo() {
    // something using $mysqli;
  }
}

To fix it, I have to add global $mysqli into my foo method - I understand that, but this isn't very practical for me, as I'd prefer to simply make $mysqli accessible within all classes by default.

Is this possible?

Lucas
  • 15,579
  • 27
  • 98
  • 170

4 Answers4

1

The short answer is: no. There isn't a way to change the way scope is handled in PHP.

Since that's probably not very helpful to you, I'll try to explain a better approach.

The global keyword is one of PHP's idiosyncrasies. Some people think it's dumb, but there's a certain logic to it. Lots of patterns in programming are about keeping dependencies explicit. Stuff that happens inside your class shouldn't depend on the state of the world outside. In your case (or whenever you import a global variable using global, you're coupling your class to the environment it lives in. This is bad for various reasons.

If your class requires a database connection, you should be injecting the dependency explicitly, not implicitly pulling it from global scope.

If the dependency is required for the class to function, the obvious place to inject it is in the constructor.

For example:

<?php

class MyComponent
{
    /**
     * @param mysqli $mysqli
     */
    public function __construct($mysqli)
    {
        $this->mysqli = $mysqli;
    }

    public function getBars()
    {
        $bars = $this->mysqli->query('...');
        return $bars;
    }
}

// now back in the global scope

$mysqli = mysqli_connect('localhost', 'joe', 'secret', 'foodb');

$component = new MyComponent($mysqli);

$bars = $component->getBars();
Community
  • 1
  • 1
timdev
  • 57,660
  • 6
  • 74
  • 90
1

For some project it is completely acceptable to have a single database and connection to it. Willing to access it from everywhere without using nasty global or injecting it all over the place make perfect sense.

One way I did is was simply to have my connection in a Static Object which is accessible from anywhere in my project. How I got this to work:

  1. Use Composer to autoload my classes without having to worry about it. There are some details about how to do this here: Using Composer's Autoload
  2. Create a class for the database connection.
class Database
{
    public static $connection;

    public static function connect($host, $user, $password, $database)
    {
        self:$connection = mysqli_connect($host, $user, $password, $database);
    }
}
  1. You can now access Database::$connection from anywhere as long as Composer includes your Database class. No need for globals...

Static classes can be quite useful for these type of usage. But some people don't like them because they are harder to test in some cases. There is no perfect solution, but do what make sense while trying to avoid bad patterns at all costs.

Community
  • 1
  • 1
Nicolas Bouvrette
  • 2,903
  • 1
  • 23
  • 43
0

You may send it into constructor:

      class Component {

           protected $mysqli;

           public function Component($mysqli = null) {
                $this->mysqli = $mysqli;
           }  

          public function foo() {
             // something using $mysqli;
           }
      }

or set it by other methot of class after creating:

     class Component {

         protected $mysqli;

         public function SetDBClass($mysqli) 
            {
                $this->mysqli = $mysqli;
            }  

     public function foo() 
        {
             // something using $mysqli;
         }
     }
0
  1. Use global keyword before declaration of your variable
  2. Or put it into $GLOBALS array.
    For more information about variable scope, take a look at this link: http://php.net/manual/en/language.variables.scope.php#language.variables.scope.global
Khalil Laleh
  • 922
  • 8
  • 16