Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 285
Josef Avatar asked Dec 04 '22 04:12

Josef


2 Answers

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.

like image 103
Josef Avatar answered Dec 19 '22 16:12

Josef


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.

like image 25
jpic Avatar answered Dec 19 '22 16:12

jpic