Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Call to a member function on a non-object

Status
Not open for further replies.

waydown

Programmer
Apr 27, 2009
49
GB
Hi,
I have the following class:

Code:
class User
    {  private $_db;
       
       public function __construct($user = null)
       {
          $this->_db = DB::getInstance();
           .......
       }
       public function find($user = null)
       { if($user)
         { $field = (is_numeric($user)) ? 'id' : 'username';
         $data = $this->_db->get('users', array($field, '=', $user));
           if($data->count())
           { .........
             return true;
           }
         }
         return false;
       }

In class DB I have:

Code:
public static function getInstance()
      { if(!(self::$_instance)): self::$_instance = new self(); 
        endif;
        return self::$_instance;
      }

public function get() in class DB, after processing, returns $this, the single instance of class DB, this is assigned to $data which is then used to invoke public function count(), a member function of class DB. I am getting the following error:

Fatal error: Call to a member function count() on a non-object.

I would be very grateful if someone can point out my mistake.
 
i think you'd need to show us all the code.

the use of static methods and singletons is always a bit tricksy. likewise chaining of static methods.

 
Hi,
I have now included all of the relevant code. The code relating to PDO I got off the internet with which I am not fully conversant:
In class User:

Code:
public function find($user = null)
   { if($user)        //if username is passed, not null
     { $field = (is_numeric($user)) ? 'id' : 'username';
       $data = $this->_db->get('users', array($field, '=', $user));
       if($data->count())
       { $this->_data = $data->first();
         return true;
       }
     }
     return false;
   }

In class DB:

Code:
class DB
    {
       private static $_instance = null;
       private $_pdo,
               $_query,
               $_error = false,
               $_results,
               $_count = 0;

      private function __construct()
      { try
        { $dsn = sprintf( "mysql:host='';dbname='';", 
                          Config::get('mysql/host'), 
                          Config::get('mysql/database')
                       );
          $this->_pdo = new PDO( $dsn, Config::get('mysql/username'), Config::get('mysql/password'));
        }
        catch(PDOException $excp)
        { die($excp->getMessage());
        }
      }

      public static function getInstance()
      { if(!(self::$_instance)): self::$_instance = new self(); 
        endif;
        return self::$_instance;
      }

       public function get($table, $where)
       { return $this->action('SELECT*', $table, $where);
       }

       public function action($action, $table, $where = array())
       { if(count($where) === 3)    //field, operator, value
         { $operators = array('=', '>', '<', '>=', '<=');

           $field    = $where[0];
           $operator = $where[1];
           $value    = $where[2];

           if(in_array($operator, $operators))
           { $sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
             if(!$this->query($sql, array($value))->error())
             { return $this;      //if not an error return $this
             }
           }
         }
         return false;   //outside of everything return false
       }

      public function query($sql, $darams = array())
      { 
        $this->_error = false;
        if($this->_query = $this->_pdo->prepare($sql))
        { $x = 1;
          if(count($darams))
          { foreach($darams as $param)
            { $this->_query->bindValue($x, $param);
              $x++;
            }
          }
          if($this->_query->execute())
          { $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
            $this->_count = $this->_query->rowCount();
          }
          else      //an error has occured in SQL query
          { $this->_error = true;
          }
        }
        return $this;
      }
 
the action method can return false.

the get method is incorrect.

Code:
public function get($table, $where)
       { return $this->action('SELECT*', $table, $where);
       }

there should be a space between SELECT and *

this line
Code:
if(!$this->query($sql, array($value))->error())
looks most bizarre as there is no error() method of the DB class.

forgetting the chaining for a moment (after all, why is chaining necessary here) perhaps this construct would be rather easier

Code:
$this->query($sql, array($value));
if(isset($this->_error) && $this->_error != ''):
 return false;
else:
 return $this;
endif;

and then really remember to check for false in your calling code. If you are never going to return false then remember that you must check for the presence of an error before you doing anything else. Hence why chaining is far from sensible on database abstraction layers.

note also that there is no count() method in DB either. so this will always throw a fatal error.
 
Hello,
Thanks for the reply. I will study and apply your suggestions. Just wanted to say that there are error and count functions which I forgot to include but I don't think they make too much difference.

Code:
public function error()
       { return $this->_error;
       }

       public function count()
       { return $this->_count;
       }
 
perhaps not. however the point is that the action method can return false. thus the get method can return false

so here, when you get to the conditional, you are asking PHP to invoke a method (count()) on a variable that is not an object but boolean false. So you must always check for boolean false
Code:
$data = $this->_db->get('users', array($field, '=', $user));
if($data !== false && $data->count() > 0):
  $this->_data = $data->first();
  return true;
endif;

but I say again that you are creating multiple instances of the same object. which I can't believe is sensible. For example here:

Code:
$data = $this->_db->get('users', array($field, '=', $user));
at this point you have $data and $this->_db which are identical. why bother chaining? If you're trying to create efficiency of code you'd be better off at creating an inheritable database abstraction class and a single global instance of the $pdo variable.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top