Link to home
Create AccountLog in
Avatar of rgb192
rgb192Flag for United States of America

asked on

Fatal error: Call to a member function real_escape_string() on a non-object in

from lynda.com php object oriented tutorial

class.Address.inc
<?php

/**
 * Physical address. 
 */
class Address {
  
  const ADDRESS_TYPE_RESIDENCE = 1;
  const ADDRESS_TYPE_BUSINESS = 2;
  const ADDRESS_TYPE_PARK = 3;
  
  // Address types.
  static public $valid_address_types = array(
    Address::ADDRESS_TYPE_RESIDENCE => 'Residence',
    Address::ADDRESS_TYPE_BUSINESS => 'Business',
    Address::ADDRESS_TYPE_PARK => 'Park',
  );
  
  // Street address.
  public $street_address_1;
  public $street_address_2;
  
  // Name of the City.
  public $city_name;
  
  // Name of the subdivison.
  public $subdivision_name;
  
  // Postal code.
  protected $_postal_code;
  
  // Name of the Country.
  public $country_name;
  
  // Primary key of an Address.
  protected $_address_id;
  
  // Address type id.
  protected $_address_type_id;
  
  // When the record was created and last updated.
  protected $_time_created;
  protected $_time_updated;
  
  /**
   * Constructor.
   * @param array $data Optional array of property names and values.
   */
  function __construct($data = array()) {
    $this->_time_created = time();
    
    // Ensure that the Address can be populated.
    if (!is_array($data)) {
      trigger_error('Unable to construct address with a ' . get_class($name));
    }
    
    // If there is at least one value, populate the Address with it.
    if (count($data) > 0) {
      foreach ($data as $name => $value) {
        // Special case for protected properties.
        if (in_array($name, array(
          'time_created',
          'time_updated',
        ))) {
          $name = '_' . $name;
        }
        $this->$name = $value;
      }
    }
  }
  
  /**
   * Magic __get.
   * @param string $name 
   * @return mixed
   */
  function __get($name) {
    // Postal code lookup if unset.
    if (!$this->_postal_code) {
      $this->_postal_code = $this->_postal_code_guess();
    }
    
    // Attempt to return a protected property by name.
    $protected_property_name = '_' . $name;
    if (property_exists($this, $protected_property_name)) {
      return $this->$protected_property_name;
    }
    
    // Unable to access property; trigger error.
    trigger_error('Undefined property via __get: ' . $name);
    return NULL;
  }
  
  /**
   * Magic __set.
   * @param string $name
   * @param mixed $value 
   */
  function __set($name, $value) {
    // Only set valid address type id.
    if ('address_type_id' == $name) {
      $this->_setAddressTypeId($value);
      return;
    }
    // Allow anything to set the postal code.
    if ('postal_code' == $name) {
      $this->$name = $value;
      return;
    }
    
    // Unable to access property; trigger error.
    trigger_error('Undefined or unallowed property via __set(): ' . $name);
  }
  
  /**
   * Magic __toString.
   * @return string 
   */
  function __toString() {
    return $this->display();
  }
  
  /**
   * Guess the postal code given the subdivision and city name.
   * @todo Replace with a database lookup.
   * @return string 
   */
  protected function _postal_code_guess() {
    $db = Database::getInstance();
    $mysqli = $db->getConnection();
    $sql_query = 'SELECT postal_code ';
    $sql_query.= 'FROM location ';
    
    $city_name = $mysqli->real_escape_string($this->city_name);
    $sql_query .= 'WHERE city_name = "' . $city_name . '" ';
    
    $subdivision_name = $mysqli->real_escape_string($this->subdivision_name);
    $sql_query .= 'AND subdivision_name = "' .$subdivision_name . '"';
    
    $result = $mysqli->query($sql_query);
    
    if ($row = $result->fetch_assoc()){
      return $row['postal_code'];
    }
  }
  
  /**
   * Display an address in HTML.
   * @return string 
   */
  function display() {
    $output = '';
    
    // Street address.
    $output .= $this->street_address_1;
    if ($this->street_address_2) {
      $output .= '<br/>' . $this->street_address_2;
    }
    
    // City, Subdivision Postal.
    $output .= '<br/>';
    $output .= $this->city_name . ', ' . $this->subdivision_name;
    $output .= ' ' . $this->postal_code;
    
    // Country.
    $output .= '<br/>';
    $output .= $this->country_name;
    
    return $output;
  }
  
  /**
   * Determine if an address type is valid.
   * @param int $address_type_id
   * @return boolean
   */
  static public function isValidAddressTypeId($address_type_id) {
    return array_key_exists($address_type_id, self::$valid_address_types);
  }
  
  /**
   * If valid, set the address type id.
   * @param int $address_type_id 
   */
  protected function _setAddressTypeId($address_type_id) {
    if (self::isValidAddressTypeId($address_type_id)) {
      $this->_address_type_id = $address_type_id;
    }
  }
}

Open in new window


class.Database.inc
<?php
/**
* mysqli database: only one connection is allowed
*/
class Database{
  private $_connection;
  //store the single instance
  private static $_instance;
  /**
  * get an instance of the database
  * @return Database
  * 
  */
  public static function getInstance(){
    if (!self::$_instance){
      self::$_instance= new self();
    }
    return self::$_instance;
  }
  /**
  * constructor
  */
  public function __construct(){
    $this->connection = new mysqli('localhost','username','pass','dbname');
    //error handling
    if (mysqli_connect_error()){
      trigger_error('Failed to connect to MySql: '.mysqli_connect_error(),E_USER_ERROR);
    }

  }
  
  
    /**
    * Empty clone magic method to prevent duplication.
    */
    private function __clone(){}
    /**
    * get the mysqli connection
    */
    public function getConnection(){
      return $this->_connection;
    }  
}

Open in new window


demo.php
<?php

require 'class.Address.inc';
require 'class.Database.inc';
echo '<h2>Instantiating Address</h2>';
$address = new Address;

echo '<h2>Setting properties...</h2>';
$address->street_address_1 = '555 Fake Street';
$address->city_name = 'Townsville';
$address->subdivision_name = 'State';
$address->country_name = 'United States of America';
$address->address_type_id = 1;
echo $address;

echo '<h2>Testing Address __construct with an array</h2>';
$address_2 = new Address(array(
  'street_address_1' => '123 Phony Ave',
  'city_name' => 'Villageland',
  'subdivision_name' => 'Region',
  'postal_code' => '67890',
  'country_name' => 'Canada',
));
echo $address_2;

Open in new window



ouput
Instantiating Address
Setting properties...

Fatal error: Call to a member function real_escape_string() on a non-object in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 134
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Looks like the error occurs in here (this starts at line 128 of Address)

  protected function _postal_code_guess() {
    $db = Database::getInstance();
    $mysqli = $db->getConnection();
    $sql_query = 'SELECT postal_code ';
    $sql_query.= 'FROM location ';
    
    $city_name = $mysqli->real_escape_string($this->city_name);
    $sql_query .= 'WHERE city_name = "' . $city_name . '" ';
    
    $subdivision_name = $mysqli->real_escape_string($this->subdivision_name);
    $sql_query .= 'AND subdivision_name = "' .$subdivision_name . '"';
    
    $result = $mysqli->query($sql_query);
    
    if ($row = $result->fetch_assoc()){
      return $row['postal_code'];
    }
  }

Open in new window

Suggest you use our friend var_dump() to see what is contained in the variables.

It may not be related, but this code looks a bit goofy, like perhaps it is incomplete?  In the constructor at line 54 we have this:

trigger_error('Unable to construct address with a ' . get_class($name));

At that point the variable $name is undefined.  Code smell.
Avatar of rgb192

ASKER

var_dump($address)
object(Address)#1 (10) { ["street_address_1"]=> string(15) "555 Fake Street" ["street_address_2"]=> NULL ["city_name"]=> string(10) "Townsville" ["subdivision_name"]=> string(5) "State" ["_postal_code:protected"]=> NULL ["country_name"]=> string(24) "United States of America" ["_address_id:protected"]=> NULL ["_address_type_id:protected"]=> int(1) ["_time_created:protected"]=> int(1377861541) ["_time_updated:protected"]=> NULL }

I can not see the output for
var_dump($address2)



also when I comment $mysqli->real_escape_string

I get this new error

Fatal error: Call to a member function query() on a non-object in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140
See also line 23 of class Database.  The connection is made with OOP notation, but the error test is made with procedural code.  I don't know if that would cause an error to be overlooked because I would never try something like that.  I think you want to change the if (mysqli_connect_error()) to if ($mysqli->connect_error)
http://php.net/manual/en/mysqli.connect-error.php

public function __construct(){
    $this->connection = new mysqli('localhost','username','pass','dbname');
    //error handling
    if (mysqli_connect_error()){
      trigger_error('Failed to connect to MySql: '.mysqli_connect_error(),E_USER_ERROR);
    }

Open in new window

Avatar of rgb192

ASKER

if ($mysqli->connect_error)

database still connects

in demo.php
var_dump($db);
var_dump($mysqli);

NULL NULL

I do not see any output when I add to postal code function
var_dump($db);
var_dump($mysqli);
Fatal error: Call to a member function [...] on a non-object...

Is your $mysqli variable properly initialized ??
well... you cannot query() on a NULL object, sorry :(
Avatar of rgb192

ASKER

when I put var_dump($db) after the $db = Database::getInstance();
object(Database)#2 (2) { ["_connection:private"]=> NULL ["connection"]=> object(mysqli)#3 (0) { }

var_dump($mysqli) after
 $mysqli = $db->getConnection();

NULL
Avatar of rgb192

ASKER

>>Is your $mysqli variable properly initialized ??

how to check
The constructor says

$this->connection

getConnection() says

return $this->_connection;

You need to get those two things to be the same, then try it again.  Probably you want to use the one with the leading underscore because of this:

private $_connection;

Also, are you using error_reporting(E_ALL) ?
Avatar of rgb192

ASKER

this is mysql, which I can see in mysql workbench query editor
CREATE TABLE IF NOT EXISTS `address` (
  `address_id` int(11) NOT NULL AUTO_INCREMENT,
  `address_type_id` int(11) NOT NULL,
  `time_created` int(11) NOT NULL,
  `time_updated` int(11) NOT NULL,
  `street_address_1` varchar(255) NOT NULL,
  `street_address_2` varchar(255) NOT NULL,
  `city_name` varchar(255) NOT NULL,
  `subdivision_name` varchar(255) NOT NULL,
  `postal_code` varchar(20) NOT NULL,
  `country_name` varchar(255) NOT NULL,
  PRIMARY KEY (`address_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

INSERT INTO `address` (`address_id`, `address_type_id`, `time_created`, `time_updated`, `street_address_1`, `street_address_2`, `city_name`, `subdivision_name`, `postal_code`, `country_name`) VALUES
(1, 1, 762483360, 0, '300 Oracle Parkway', '', 'Redwood City', 'California', '94065', 'United States');

CREATE TABLE IF NOT EXISTS `location` (
  `location_id` int(11) NOT NULL AUTO_INCREMENT,
  `city_name` varchar(255) NOT NULL,
  `city_latitude` double NOT NULL,
  `city_longitude` double NOT NULL,
  `subdivision_name` varchar(255) NOT NULL,
  `postal_code` varchar(20) NOT NULL,
  PRIMARY KEY (`location_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;

INSERT INTO `location` (`location_id`, `city_name`, `city_latitude`, `city_longitude`, `subdivision_name`, `postal_code`) VALUES
(1, 'Townsville', 38.7153408676386, -75.0866805016994, 'State', '12345'),
(2, 'Villageland', 33.1156463623047, -117.120277404785, 'Region', '67890'),
(3, 'Hamlet', 43.6666296, -92.9746367, 'Territory', '34567'),
(4, 'Redwood City', 37.5311965942383, -122.2646484375, 'California', '94065');

Open in new window

The queries are (probably) OK.  It's the use of an uninitialized variable that's causing the problem -- at least that's what I think.

Class Database, line 24

$this->_connection = new mysqli('localhost','username','pass','dbname');
Avatar of rgb192

ASKER

where does the

The constructor says

$this->connection


  function __construct($data = array()) {
    $this->_time_created = time();
    
    // Ensure that the Address can be populated.
    if (!is_array($data)) {
      trigger_error('Unable to construct address with a ' . get_class($name));
    }
    
    // If there is at least one value, populate the Address with it.
    if (count($data) > 0) {
      foreach ($data as $name => $value) {
        // Special case for protected properties.
        if (in_array($name, array(
          'time_created',
          'time_updated',
        ))) {
          $name = '_' . $name;
        }
        $this->$name = $value;
      }
    }
  }

Open in new window

Avatar of rgb192

ASKER

The queries are (probably) OK.  It's the use of an uninitialized variable that's causing the problem -- at least that's what I think.

Class Database, line 24

$this->_connection = new mysqli('localhost','username','pass','dbname');


I am using my database connection (which I do not show to experts-exchange.com)


now with
error_reporting(E_ALL)

output is
Instantiating Address
Setting properties...
object(Address)#1 (10) { ["street_address_1"]=> string(15) "555 Fake Street" ["street_address_2"]=> NULL ["city_name"]=> string(10) "Townsville" ["subdivision_name"]=> string(5) "State" ["_postal_code:protected"]=> NULL ["country_name"]=> string(24) "United States of America" ["_address_id:protected"]=> NULL ["_address_type_id:protected"]=> int(1) ["_time_created:protected"]=> int(1377863706) ["_time_updated:protected"]=> NULL }
Notice: Undefined variable: db in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 15
NULL
Notice: Undefined variable: mysqli in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 16
NULL
Notice: Use of undefined constant connect_error - assumed 'connect_error' in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Database.inc on line 26

Notice: Undefined variable: mysqli_ in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Database.inc on line 26
object(Database)#2 (2) { ["_connection:private"]=> NULL ["connection"]=> object(mysqli)#3 (0) { } } whatNULL
Fatal error: Call to a member function query() on a non-object in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140
I believe the error is in Class.Database.inc which is posted above with the original question.

Have a look at this:
object(Database)#2 (2) {
["_connection:private"]=> NULL
["connection"]=> object(mysqli)#3 (0) { }
}

What that tells me is that I am looking at the var_dump() output of an object instance of the Database class.  The object has two properties.  The _connection property is private and NULL (this is because it was declared private in the class definition, but no value was assigned).  The connection property contains an object instance of the mysqli class.  Note the difference between these two properties -- one starts with a leading underscore and is private.  The other is apparently accidentally created by a typographical error in the Database class constructor.
Avatar of rgb192

ASKER

So how could I
var_dump from the database class
or
edit the database class
Let's try this.  Go find the Database class that you're actually using in these tests.  Blot out the password, then post the entire Database class in the code snippet here.  I'll show you what I think needs to change.
OK, I think I was confused by this:
I am using my database connection (which I do not show to experts-exchange.com)
I will post a new version of the class.Database.inc in a moment.  I just want to make sure you understand the change I'm making and how to find out where the error has been hiding.
See if this makes sense.
<?php // class.Database.inc
/**
* mysqli database: only one connection is allowed
*/
class Database
{
    private $_connection;
    //store the single instance
    private static $_instance;
    /**
    * get an instance of the database
    * @return Database
    */
    public static function getInstance(){
        if (!self::$_instance){
            self::$_instance= new self();
        }
        return self::$_instance;
    }
    /**
    * constructor
    */
    public function __construct(){
        $this->_connection = new mysqli('localhost','username','pass','dbname');
        //error handling
        if ($this->_connection->_connect_error){
            trigger_error('Failed to connect to MySql: '.mysqli_connect_error(),E_USER_ERROR);
        }
    }
    
    
    /**
    * Empty clone magic method to prevent duplication.
    */
    private function __clone(){}
    /**
    * get the mysqli connection
    */
    public function getConnection(){
        return $this->_connection;
    }  
}

Open in new window

I have tested this version of it.  The only changes I made before posting here are the authentication credentials.

The problem with this Database class is that it is not a "real" Singleton, in that it does not enforce the policy that requires only one connection to the data base.  Because it can be instantiated, you can wind up with multiple data base connections.  

In the next post, I will show you a real Singleton.

<?php // RWY_temp_rgb192.php
error_reporting(E_ALL);
/**
* mysqli database: only one connection is allowed (BUT THIS IS NOT A TRUE SINGLETON)
*/
class Database
{
    private $_connection;
    //store the single instance
    private static $_instance;
    /**
    * get an instance of the database
    * @return Database
    */
    public static function getInstance(){
        if (!self::$_instance){
            self::$_instance= new self();
        }
        return self::$_instance;
    }
    /**
    * constructor
    */
    public function __construct(){
        $this->_connection = new mysqli('localhost','user','pass','name');
        //error handling
        if ($this->_connection->connect_error){
            trigger_error('Failed to connect to MySql: '.mysqli_connect_error(),E_USER_ERROR);
        }
    }


    /**
    * Empty clone magic method to prevent duplication.
    */
    private function __clone(){}
    /**
    * get the mysqli connection
    */
    public function getConnection(){
        return $this->_connection;
    }
}
// CREATE INSTANCES
$db1 = new Database;
$db2 = $db1->getConnection();
$db3 = new Database;
$db4 = $db3->getConnection();
$db5 = $db3->getConnection();

// THIS WILL PROVE THAT THERE ARE TWO CONNECTIONS (NO ECHO)
if ($db2 === $db4) echo 'EQUAL';

// THIS WILL SHOW THAT CONNECTIONS FROM THE SAME INSTANCE ARE EQUAL
if ($db4 === $db5) echo 'CONNECTION EQUAL';

Open in new window

This is a true Singleton class.  It cannot be instantiated, therefore you cannot wind up with any instance of the object, much less several instances of the object.  And since it will always return a private class property representing the MySQLi connection, you can be sure that any access to the Database will be using the same connection.

I believe that the only thing we want back from this is the connection, not the internal instance, so I changed the getInstance() to eliminate that additional step.

<?php // RAY_database_singleton.php
error_reporting(E_ALL);


// SINGLETON DATA BASE CONNECTION CLASS
class Database
{
    // CLASS PROPERTIES ARE ALL PRIVATE
    private static $_connection;
    private static $_instance;

    // CONNECTION VALUES
    const DB_HOST = 'localhost';
    const DB_USER = 'user';
    const DB_PASS = 'pass';
    const DB_NAME = 'name';

    // NULLIFY THE CLONE
    private function __clone() {}

    // OUR ONLY PUBLIC METHOD RETURNS THE CONNECTION
    public static function getConnection()
    {
        if (!self::$_instance) self::$_instance = new self();
        return self::$_connection;
    }

    // CONSTRUCTOR RETURNS THE CONNECTION
    private function __construct()
    {
        self::$_connection
        = new mysqli
        ( self::DB_HOST
        , self::DB_USER
        , self::DB_PASS
        , self::DB_NAME
        )
        ;
        if (self::$_connection->connect_error)
        {
            trigger_error(self::$_connection->connect_error, E_USER_ERROR);
        }
    }
}

$mysql1 = database::getConnection();
$mysql2 = database::getConnection();


// PROVE THAT THESE ARE THE SAME OBJECT http://php.net/manual/en/language.oop5.object-comparison.php
if ($mysql1 === $mysql2) echo 'EQUAL';

Open in new window

HTH, ~Ray
Avatar of rgb192

ASKER

output of
https://www.experts-exchange.com/questions/28226938/Fatal-error-Call-to-a-member-function-real-escape-string-on-a-non-object-in.html?anchorAnswerId=39452593#a39452593

EQUAL
Instantiating Address
Setting properties...
object(Address)#3 (10) { ["street_address_1"]=> string(15) "555 Fake Street" ["street_address_2"]=> NULL ["city_name"]=> string(10) "Townsville" ["subdivision_name"]=> string(5) "State" ["_postal_code:protected"]=> NULL ["country_name"]=> string(24) "United States of America" ["_address_id:protected"]=> NULL ["_address_type_id:protected"]=> int(1) ["_time_created:protected"]=> int(1377885590) ["_time_updated:protected"]=> NULL }
Notice: Undefined variable: db in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 15
NULL
Notice: Undefined variable: mysqli in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 16
NULL
Fatal error: Call to undefined method Database::getInstance() in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 129
Avatar of rgb192

ASKER

output of
https://www.experts-exchange.com/questions/28226938/Fatal-error-Call-to-a-member-function-real-escape-string-on-a-non-object-in.html?anchorAnswerId=39452571#a39452571

CONNECTION EQUAL
Instantiating Address
Setting properties...
object(Address)#5 (10) { ["street_address_1"]=> string(15) "555 Fake Street" ["street_address_2"]=> NULL ["city_name"]=> string(10) "Townsville" ["subdivision_name"]=> string(5) "State" ["_postal_code:protected"]=> NULL ["country_name"]=> string(24) "United States of America" ["_address_id:protected"]=> NULL ["_address_type_id:protected"]=> int(1) ["_time_created:protected"]=> int(1377885797) ["_time_updated:protected"]=> NULL }
Notice: Undefined variable: db in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 15
NULL
Notice: Undefined variable: mysqli in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 16
NULL object(Database)#6 (1) { ["_connection:private"]=> object(mysqli)#7 (0) { } } whatobject(mysqli)#7 (0) { }
Notice: Undefined variable: sql_query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Warning: mysqli::query() [mysqli.query]: Empty query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Fatal error: Call to a member function fetch_assoc() on a non-object in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 142
Avatar of rgb192

ASKER

output of
https://www.experts-exchange.com/questions/28226938/Fatal-error-Call-to-a-member-function-real-escape-string-on-a-non-object-in.html?anchorAnswerId=39452502#a39452502

Instantiating Address
Setting properties...
object(Address)#1 (10) { ["street_address_1"]=> string(15) "555 Fake Street" ["street_address_2"]=> NULL ["city_name"]=> string(10) "Townsville" ["subdivision_name"]=> string(5) "State" ["_postal_code:protected"]=> NULL ["country_name"]=> string(24) "United States of America" ["_address_id:protected"]=> NULL ["_address_type_id:protected"]=> int(1) ["_time_created:protected"]=> int(1377885928) ["_time_updated:protected"]=> NULL }
Notice: Undefined variable: db in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 15
NULL
Notice: Undefined variable: mysqli in C:\wamp\www\Ex_Files_oophp-edit\04_05\demo.php on line 16
NULL
Notice: Undefined property: mysqli::$_connect_error in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Database.inc on line 26
object(Database)#2 (1) { ["_connection:private"]=> object(mysqli)#3 (0) { } } whatobject(mysqli)#3 (0) { }
Notice: Undefined variable: sql_query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Warning: mysqli::query() [mysqli.query]: Empty query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Fatal error: Call to a member function fetch_assoc() on a non-object in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 142
ASKER CERTIFIED SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
Avatar of rgb192

ASKER

QUERY: SELECT 1+1
FOUND 1 ROWS OF DATA USING MySQLi_Result::Fetch_Object(): stdClass Object ( [1+1] => 2 )
Instantiating Address
Setting properties...
object(Address)#4 (10) { ["street_address_1"]=> string(15) "555 Fake Street" ["street_address_2"]=> NULL ["city_name"]=> string(10) "Townsville" ["subdivision_name"]=> string(5) "State" ["_postal_code:protected"]=> NULL ["country_name"]=> string(24) "United States of America" ["_address_id:protected"]=> NULL ["_address_type_id:protected"]=> int(1) ["_time_created:protected"]=> int(1377895740) ["_time_updated:protected"]=> NULL } object(Database)#1 (1) { ["_connection:private"]=> object(mysqli)#2 (0) { } } object(mysqli)#2 (0) { } object(Database)#1 (1) { ["_connection:private"]=> object(mysqli)#2 (0) { } } whatobject(mysqli)#2 (0) { }
Notice: Undefined variable: sql_query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Warning: mysqli::query() [mysqli.query]: Empty query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Fatal error: Call to a member function fetch_assoc() on a non-object in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 142



output after commenting var_dump
QUERY: SELECT 1+1
FOUND 1 ROWS OF DATA USING MySQLi_Result::Fetch_Object(): stdClass Object ( [1+1] => 2 )
Instantiating Address
Setting properties...

Notice: Undefined variable: sql_query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Warning: mysqli::query() [mysqli.query]: Empty query in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 140

Fatal error: Call to a member function fetch_assoc() on a non-object in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 142



I noticed that I added echo and var_dump in class.Address.inc and demo.php, changing the values so I copy paste those files

current version of class.Address.inc
<?php

/**
 * Physical address. 
 */
class Address {
  
  const ADDRESS_TYPE_RESIDENCE = 1;
  const ADDRESS_TYPE_BUSINESS = 2;
  const ADDRESS_TYPE_PARK = 3;
  
  // Address types.
  static public $valid_address_types = array(
    Address::ADDRESS_TYPE_RESIDENCE => 'Residence',
    Address::ADDRESS_TYPE_BUSINESS => 'Business',
    Address::ADDRESS_TYPE_PARK => 'Park',
  );
  
  // Street address.
  public $street_address_1;
  public $street_address_2;
  
  // Name of the City.
  public $city_name;
  
  // Name of the subdivison.
  public $subdivision_name;
  
  // Postal code.
  protected $_postal_code;
  
  // Name of the Country.
  public $country_name;
  
  // Primary key of an Address.
  protected $_address_id;
  
  // Address type id.
  protected $_address_type_id;
  
  // When the record was created and last updated.
  protected $_time_created;
  protected $_time_updated;
  
  /**
   * Constructor.
   * @param array $data Optional array of property names and values.
   */
  function __construct($data = array()) {
    $this->_time_created = time();
    
    // Ensure that the Address can be populated.
    if (!is_array($data)) {
      trigger_error('Unable to construct address with a ' . get_class($name));
    }
    
    // If there is at least one value, populate the Address with it.
    if (count($data) > 0) {
      foreach ($data as $name => $value) {
        // Special case for protected properties.
        if (in_array($name, array(
          'time_created',
          'time_updated',
        ))) {
          $name = '_' . $name;
        }
        $this->$name = $value;
      }
    }
  }
  
  /**
   * Magic __get.
   * @param string $name 
   * @return mixed
   */
  function __get($name) {
    // Postal code lookup if unset.
    if (!$this->_postal_code) {
      $this->_postal_code = $this->_postal_code_guess();
    }
    
    // Attempt to return a protected property by name.
    $protected_property_name = '_' . $name;
    if (property_exists($this, $protected_property_name)) {
      return $this->$protected_property_name;
    }
    
    // Unable to access property; trigger error.
    trigger_error('Undefined property via __get: ' . $name);
    return NULL;
  }
  
  /**
   * Magic __set.
   * @param string $name
   * @param mixed $value 
   */
  function __set($name, $value) {
    // Only set valid address type id.
    if ('address_type_id' == $name) {
      $this->_setAddressTypeId($value);
      return;
    }
    // Allow anything to set the postal code.
    if ('postal_code' == $name) {
      $this->$name = $value;
      return;
    }
    
    // Unable to access property; trigger error.
    trigger_error('Undefined or unallowed property via __set(): ' . $name);
  }
  
  /**
   * Magic __toString.
   * @return string 
   */
  function __toString() {
    return $this->display();
  }
  
  /**
   * Guess the postal code given the subdivision and city name.
   * @todo Replace with a database lookup.
   * @return string 
   */
  protected function _postal_code_guess() {
    $db = Database::getInstance();
    //var_dump($db);
    $mysqli = $db->getConnection();
    //echo 'what';
    //var_dump($mysqli);    
    $city_name = /*$mysqli->real_escape_string(*/$this->city_name/*)*/;
    //$sql_query .= 'WHERE city_name = "' . $city_name . '" ';
    
    $subdivision_name = /*$mysqli->real_escape_string(*/$this->subdivision_name/*)*/;
    //$sql_query .= 'AND subdivision_name = "' .$subdivision_name . '"';
    
    $result = $mysqli->query($sql_query);
    
    if ($row = $result->fetch_assoc()){
      return $row['postal_code'];
    }
    //var_dump($db);
//var_dump($mysqli);
  }
  
  /**
   * Display an address in HTML.
   * @return string 
   */
  function display() {
    $output = '';
    
    // Street address.
    $output .= $this->street_address_1;
    if ($this->street_address_2) {
      $output .= '<br/>' . $this->street_address_2;
    }
    
    // City, Subdivision Postal.
    $output .= '<br/>';
    $output .= $this->city_name . ', ' . $this->subdivision_name;
    $output .= ' ' . $this->postal_code;
    
    // Country.
    $output .= '<br/>';
    $output .= $this->country_name;
    
    return $output;
  }
  
  /**
   * Determine if an address type is valid.
   * @param int $address_type_id
   * @return boolean
   */
  static public function isValidAddressTypeId($address_type_id) {
    return array_key_exists($address_type_id, self::$valid_address_types);
  }
  
  /**
   * If valid, set the address type id.
   * @param int $address_type_id 
   */
  protected function _setAddressTypeId($address_type_id) {
    if (self::isValidAddressTypeId($address_type_id)) {
      $this->_address_type_id = $address_type_id;
    }
  }
}

Open in new window


current version of demo.php
<?php
error_reporting(E_ALL);
require 'class.Address.inc';
require 'class.Database.inc';
echo '<h2>Instantiating Address</h2>';
$address = new Address;

echo '<h2>Setting properties...</h2>';
$address->street_address_1 = '555 Fake Street';
$address->city_name = 'Townsville';
$address->subdivision_name = 'State';
$address->country_name = 'United States of America';
$address->address_type_id = 1;
//var_dump($address);
//var_dump($db);
//var_dump($mysqli);
echo $address;

echo '<h2>Testing Address __construct with an array</h2>';
$address_2 = new Address(array(
  'street_address_1' => '123 Phony Ave',
  'city_name' => 'Villageland',
  'subdivision_name' => 'Region',
  'postal_code' => '67890',
  'country_name' => 'Canada',
));
//var_dump($address2);
echo $address_2;

Open in new window

Looks like the _postal_code_guess() function is damaged by comments.  What should be in that function? Suggest you restore it to its original state and try the tests again
Avatar of rgb192

ASKER

Using wamp on my desktop and linux server I get the same warnings and fatal error.
Then you're probably not running the original script.  Please revert to the original script for class.Address.inc, check to be sure it has the correct query in the _postal_code_guess() function and try again.

You might want to learn about GIT or SubVersion so you don't run the risk of losing a prior version of your software to an accidental overwrite.
Avatar of rgb192

ASKER

with the original class.Address

all your examples worked except
https://www.experts-exchange.com/questions/28226938/Fatal-error-Call-to-a-member-function-real-escape-string-on-a-non-object-in.html?anchorAnswerId=39452593#a39452593

Fatal error: Call to undefined method Database::getInstance() in C:\wamp\www\Ex_Files_oophp-edit\04_05\class.Address.inc on line 129