Josef
Josef

Reputation: 161

Global variables inside functions value is NULL

In my code I have a file that initializes a MySQLi class.

File a:

$db = new Database(); //MySQLi class

Anyways, there is a file that includes this database class. That file also includes other files that has function declared in it. I'm using global to contact $db

File b:

function xy(){
   global $db;
   $sql = "..."
   return $db->getArray($sql);
}

Testfile:

require "file_a.php";
require "file_b.php";
require_once "PHPUnit/Framework/TestCase.php";

class testProblemStatistics extends PHPUnit_Framework_TestCase {

  testArray(){
      $this->assertTrue(array_key_exists('xy', $this->xy())
  }
}

I get:
Fatal error: Call to a member function getArray() on a non-object

I investigated:

var_dump($db);
function xy(){
  global $db;
  var_dump($db);
  ...
}

The first dump gave me the MySQLi object,
the second dump gave me NULL

Something is wrong with the global variable in file_b.

Additional Information: I'm using PHPUnit and I'm running it in the command prompt. In a normal browser everything works fine.

Upvotes: 5

Views: 6532

Answers (3)

Andreas Borg
Andreas Borg

Reputation: 51

It seems that when run in PHPUnit, the top-level code in file a is run inside some method and the assignment to $db refers to a local variable. Make it explicitely global so that it stays that way in the test run:

global $db;
$db = new Database(); //MySQLi class

Upvotes: 3

Josef
Josef

Reputation: 161

The Solution is to hardcode the Database Class into the $GLOBALS Array.

$GLOBALS['db'] = $db;

Adding this as a PHPUnit bootstrap worked fine for me. It is kind of hacky and should be used in Test cases.

Upvotes: 11

jpic
jpic

Reputation: 33420

You must fully understand PHPUnit's manual on Global State:

By default, PHPUnit runs your tests in a way where changes to global and super-global variables ($GLOBALS, $_ENV, $_POST, $_GET, $_COOKIE, $_SERVER, $_FILES, $_REQUEST) do not affect other tests. Optionally, this isolation can be extended to static attributes of classes.

Very likely, the $db global variable is created during a test. Thus, it is erased back to null after the test. You could either set the global variable in setUp(), either manage yourself how you want PHPUnit to behave with this global. There are several ways to do that.

Switch the value of @backupGlobals and it won't do the backup/restore operation between tests:

<?php

function xy(  ) {
    global $foo;
    var_dump( $foo ); 
    return $foo;
}

/**
 * @backupGlobals disabled
 */
class someTestCase extends PHPUnit_Framework_TestCase {

    public function testA(  ) {
        global $foo;
        $foo = 'bar';
    }  

    public function testB(  ) {
        global $foo;
        $this->assertEquals( $foo, 'bar' ); 
    }  
}

Do you understand why @backupGlobals enabled make the test fail wheras @backupGlobals disabled make it pass ?

If you want backup/restore of the global variables except for $db, define such a class attribute:

protected $backupGlobalsBlacklist = array( 'db' );

This works too. Actually that would be even better since it's nice to have test isolation.

Upvotes: 4

Related Questions