Page 1 of 1

Extended class cannot access parent class variable

Posted: Sun Sep 23, 2007 1:00 pm
by Bon Bon
I am trying to create a database->table->field model and things are not going too well. Basically the field class does not inherit the $_table variable from the table class so the $_table variable contains no value. But everything else works.

Any ideas on what I am doing wrong?

Code: Select all

<?php
class MysqliAccess {
  static private $_instance = NULL;
  static private $_mysqli;
  protected $_table;
  protected $_result;
  protected $_where;
  private function __construct () {
    self::$_mysqli = mysqli_init();
    self::_dbConnect();
    self::_setTables();
  }
  final private function _dbConnect () {
    self::$_mysqli->real_connect('ip address', 'user', 'password', 'table');
  }
  private function _setTables () {
    $this->_query('SHOW TABLES');
    while ($row = $this->_result->fetch_row()) {
      $table = $row[0];
      $this->$table = new Table($table);
    }
  }
  final protected function _tableExists ($table) {
    // removed to shorten code
  }
  final protected function _getTableFields ($table) {
    $this->_query('SHOW COLUMNS FROM `' . $this->_escape($table) . '`');
    if ($this->_result && $this->_result->num_rows > 0) {
      while ($row = $this->_result->fetch_row()) {
        $fields[] = $row[0];
      }
      return $fields;
    }
    return FALSE;
  }
  static public function getInstance () {
    // removed to shorten code
  }
  final protected function _escape ($variable) {
    // removed to shorten code
  }
  private function _query ($sql) {
    // removed to shorten code
  }
  public function fetchSingle ($field) {
    $this->_query('SELECT `' . $this->_escape($field) . "` FROM `$this->_table` $this->_where LIMIT 1");
    if ($this->_result) return implode('', $this->_result->fetch_row());
    return FALSE;
  }
}
class Table extends MysqliAccess {
  protected $_table;
  protected function __construct ($table) {
    if ($this->_tableExists($table)) $this->_table = $table;
    if ($fields = $this->_getTableFields($this->_table)) {
      foreach ($fields as $field) {
        $this->$field = new Field($field);
      }
    }
  }
}
class Field extends Table {
  private $_field;
  protected function __construct ($field) {
    $this->_field = $field;
  }
  public function __toString () {
    return $this->fetchSingle($this->_field);
  }
}
$db = MysqliAccess::getInstance();
?>

Posted: Sun Sep 23, 2007 1:48 pm
by feyd
Table redeclares $_table thereby making the parent's not accessible from $this->_table. parent::$_table would work however.

Posted: Sun Sep 23, 2007 2:28 pm
by Bon Bon
Changing the code to the following causes the error mentioned below:

Code: Select all

class Table extends MysqliAccess {
  protected function __construct ($table) {
    if ($this->_tableExists($table)) parent::$_table = $table;
    else trigger_error("Table cannot be read from: $table.", E_USER_ERROR);

    if ($fields = $this->_getTableFields(parent::$_table)) {
      foreach ($fields as $field) {
        $this->{$field} = new Field($field);
      }
    }
  }
}
Fatal error: Access to undeclared static property: MysqliAccess::$_table

I want {$_table} to be different for every table class declared, will accessing the {$_table} variable in the parent scope still allow this?

Posted: Sun Sep 23, 2007 3:12 pm
by feyd
Hmm... I guess I confused the parent:: bit. You should be able to use $this->_table now that you've removed the redeclaration.

I'm not sure I understand why Field extends Table. A field isn't a Table. A Table is made of one or more fields however, but it's composed of fields, not a descendant of one.

Posted: Sun Sep 23, 2007 3:26 pm
by Bon Bon
Now I have done that I get the following error:

Method Field::__toString() must return a string value

This is because $this->_table still contains no value.

I am extending the table class using the field class because I want to be able to do things like:

Code: Select all

$db->table_name->field->search('value'); // finds 'value' in 'field' from the table 'table_name'
echo $db->table_name->field;
Now maybe I have misunderstood OOP because I have really just started using classes in PHP but I assumed I should be able to do this.

Posted: Sun Sep 23, 2007 3:31 pm
by feyd
The function returns false in a particular case. It cannot do that. Return an empty string.

Posted: Sun Sep 23, 2007 3:40 pm
by Bon Bon
It returns FALSE because fetchSingle returns FALSE because it is trying to run the following query:
SELECT `username` FROM `` LIMIT 1

As you can see by that, {$_table} is NULL, no value has been set and this is causing the query to fail, this is because the {$_table} variable is not being passed to the parent class. For what ever reason which I don't know, it seems strange to me because it can pass the {$_table} variable value from the Table class to the MysqliAccess but not from the Field class to the MysqliAccess class.

Posted: Mon Sep 24, 2007 10:22 am
by Chris Corbyn
Bon Bon wrote:It returns FALSE because fetchSingle returns FALSE because it is trying to run the following query:
SELECT `username` FROM `` LIMIT 1

As you can see by that, {$_table} is NULL, no value has been set and this is causing the query to fail, this is because the {$_table} variable is not being passed to the parent class. For what ever reason which I don't know, it seems strange to me because it can pass the {$_table} variable value from the Table class to the MysqliAccess but not from the Field class to the MysqliAccess class.

Code: Select all

if (empty($this->_field)) {
  return "";
} else {
  return $this->_field;
}
I agree with ~feyd that your types make no sense. A field is not a table so don't subclass table to make one. This is one of the most common mistakes newcomers to OOP make (in all OO languages).

Posted: Mon Sep 24, 2007 1:36 pm
by Bon Bon
The field name is not empty, it is the table name and that solution would do nothing to solve the problem.

The problem lies with the referencing of variables between 3 classes.

This is what I want to happen:
class 1 -> class 2 -> class 3
class 1 <- class 2 <- class 3

This is what happens:
class 1 -> class 2 -> class 3
class 1 <- class 2
class 1 <- class 3

I done some testing and using static variables I got the referencing to work using static variables but then this meant that I could only have 1 Table class and 1 Field class.

Now after I rethink I understand that I should not be extending classes like this, each class should have its own functionality and maybe sorting out what functions belong to which class might help solve the problem.

I will try splitting the classes, but in the future if I have the same problem but it made sense to pass the variable between 3 classes, each extending the parent, then I would still need a solution if anyone knows one?

Cheers for the help.