I have this parent class in PHP:
class parentClass{
public $table;
public function __construct(){
$this->table = "my_parent_table";
}
public function getName($id) {
$strQuery = "SELECT name FROM $this->table WHERE id=$id";
$result = mysql_query($strQuery);
if ($result) {
$row = mysql_fetch_object($result);
if ($row) {
return $row->name;
} else {
return false;
}
} else {
return false;
}
}
}
And I have also another class with inherits this one:
class childClass extends parentClass{
public $table;
public function __construct(){
$this->table = "my_child_table";
}
}
Then in another file I am doing:
$myObj = new childClass();
$name = $myObj->getName('1');
The problem now is that the getName function has a null table, so the variable $this->table is null, while I want it to be ""my_child_table" as long as I have a childClass object.
Does anyone know what I am doing wrong?
Thanks in advance
Not sure, but this look tricky:
class childClass extends parentClass{
public $table;
The parentClass already defines a $table, so it's likely that redeclaring it inside the child class will clobber the parent's version. You have to remove the declaration here. Also, public visibility doesn't really encapsulate the state very well; use protected in the parent instead.
public function __construct()
{
You should add parent::__construct() here (unless parent only sets $this->table, but even then it's good to add)
$this->table = "my_child_table";
}
}
Related
I have the following php code:
<?php
class ParentClass {
public $table_name;
function __construct() {
$this->table_name = strtolower(__CLASS__);
}
}
class ChildClass extends ParentClass {
function __construct() {
parent::__construct();
//And I also want to put here other codes
}
}
$parent = new ParentClass();
$child = new ChildClass();
echo $parent->table_name . "<br />" . $child->table_name;
?>
the result is
parentclass
parentclass
however I want it to be
parentclass
childclass
How do I achieve it?
Late static binding would solve my problem, however it cant be called statically of course.
http://php.net/manual/en/language.oop5.late-static-bindings.php
This works in PHP5.5 and upwards:
class ParentClass
{
public $table_name;
public function __construct()
{
$this->table_name = strtolower(static::class);
}
}
class ChildClass extends ParentClass
{
public function __construct()
{
parent::__construct();
// ...
}
}
$parent = new ParentClass();
$child = new ChildClass();
echo $parent->table_name . "<br />" . $child->table_name;
For reference, see http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class.
Use static::class to get the name of the class using late static binding:
class ParentClass {
public $table_name;
function __construct() {
$this->table_name = strtolower(static::class);
}
}
This will result in the desired
parentclass
childclass
<?php
class ParentClass {
public $table_name;
function __construct() {
$this->table_name = strtolower(__CLASS__);
}
}
class ChildClass extends ParentClass {
function __construct() {
parent::__construct();
$this->table_name = strtolower(__CLASS__);
//And I also want to put here other codes
}
}
$parent = new ParentClass();
$child = new ChildClass();
echo $parent->table_name . "" . $child->table_name;
?>
I have this code and i´m trying to use a object
<?php
class Controller {
public $_view;
public function __construct() {
$this->_view = new View();
return $this->_view;
}
}
class View {
public $_params = array ();
public function set_params($index_name,$valores) {
$this->_params[$index_name] = $valores;
}
public function get_param($index_name){
return $this->_params[$index_name];
}
}
?>
i would like to do this:
class Index extends Controller {
public function index() {
$model = Model::get_estancia();
$usuarios = $model->query("SELECT * FROM usuarios");
$this->_view->set_params(); // cant be used.
$this->load_view("index/index");
}
}
i would like to use the set_parms function.
but i can't see the View Function, then i can not use.
Can someone explain and advise me a good and safe way?
Correction from Phil: If a __construct() method isn't found, PHP will revert to legacy constructor syntax and check for a method with the same name as the object. In your case the method index() is being treated as the constructor, and is preventing the parent's constructor from loading the view object into the $_view property.
You can force a class to inherit a parent's constructor by defining __construct() in the child and calling the parent's constructor:
public function __construct() {
parent::_construct();
}
Here is the fixed code:
<?php
class Controller {
public $_view;
public function __construct() {
$this->_view = new View();
return $this->_view;
}
}
.
class View {
public $_params = array ();
public function set_params($index_name,$valores) {
$this->_params[$index_name] = $valores;
}
public function get_param($index_name){
return $this->_params[$index_name];
}
}
.
class Index extends Controller {
public function __construct() {
parent::__construct();
}
public function index() {
$model = Model::get_estancia();
$usuarios = $model->query("SELECT * FROM usuarios");
$this->_view->set_params(); // cant be used.
$this->load_view("index/index");
}
}
I have something like this:
class MyParent {
protected static $object;
protected static $db_fields;
public function delete() {
// delete stuff
}
public static function find_by_id($id = 0) {
global $database;
$result_array = self::find_by_sql("SELECT * FROM " . static::$table_name . " WHERE id=" . $database -> escape_value($id) . " LIMIT 1");
return !empty($result_array) ? array_shift($result_array) : false;
}
public static function find_by_sql($sql = "") {
global $database;
// Do Query
$result_set = $database -> query($sql);
// Get Results
$object_array = array();
while ($row = $database -> fetch_array($result_set)) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
private static function instantiate($record) {
$object = self::$object;
foreach ($record as $attribute => $value) {
if (self::has_attribute($attribute)) {
$object -> $attribute = $value;
}
}
return $object;
}
}
class TheChild extends MyParent {
protected static $db_fields = array('id', 'name');
protected static $table_name = "my_table";
function __construct() {
self::$object = new TheChild;
}
}
$child= TheChild::find_by_id($_GET['id']);
$child->delete();
I get this: Call to undefined method stdClass::delete() referring to the last line above. What step am I missing for proper inheritance?
You never actually instanciate the TheChild class, which should be done by
$var = new TheChild();
except in TheChild constructor itself.
So, the static $object field is never affected (at least in your example), so affecting a field to it (the line $object -> $attribute = $value; ) causes the creation of an stdClass object, as demonstrated in this interactive PHP shell session:
php > class Z { public static $object; }
php > Z::$object->toto = 5;
PHP Warning: Creating default object from empty value in php shell code on line 1
php > var_dump(Z::$object);
object(stdClass)#1 (1) {
["toto"]=>
int(5)
}
This object does not have a delete method.
And as said before, actually creating a TheChild instance will result in an infinite recursion.
What you want to do is this, probably:
class TheChild extends MyParent {
protected static $db_fields = array('id', 'name');
protected static $table_name = "my_table";
function __construct() {
self::$object = $this;
}
}
Edit: Your updated code shows a COMPLETE different Example:
class MyParent {
protected static $object;
public function delete() {
// delete stuff
}
}
class TheChild extends MyParent {
function __construct() {
self::$object = new TheChild;
}
}
$child = new TheChild;
$child->delete();
Calling "Child's" Constructor from within "Child's" Constructor will result in an infinite loop:
function __construct() {
self::$object = new TheChild; // will trigger __construct on the child, which in turn will create a new child, and so on.
}
Maybe - i dont know what you try to achieve - you are looking for:
function __construct() {
self::$object = new MyParent;
}
ALSO note, that the :: Notation is not just a different Version for -> - it is completely different. One is a Static access, the other is a access on an actual object instance!
I added in parent::__construct(); to the constructors of table and bookmark in order to get this code to work. Why are they not called automatically?
If I create an object of type bookmark $obj_ref_bo = new bookmark(); should not bookmark also create objects from each of its parent classes (besides abstract classes).
The call chain is
bookmark->table->database(abstract)->single_connect
/*single_connect*/
class single_connect
{
protected static $_db_pointer = NULL;
private function __construct()
{
$this->_db_pointer = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_DATABASE);
}
public static function get_connection()
{
if(self::$_db_pointer == NULL)
{
return new self();
}
else
{
echo "Error:only one connection";
}
}
}
/*database*/
abstract class database
{
protected function __construct()
{
single_connect::get_connection();
}
static protected function query($query)
{
$result = mysql_query($query) or die(mysql_error());
return $result;
}
}
/*table*/
class table extends database
{
public $_protected_arr=array();
protected function __construct()
{
parent::__construct();
$this->protect();
}
protected function protect()
{
foreach($_POST as $key => $value)
{
$this->_protected_arr[$key] = mysql_real_escape_string($value);
}
}
}
/*bookmark*/
class bookmark extends table
{
function __construct()
{
parent::__construct();
$this->start();
}
function start()
{
if(this->test())
{
this->insert();
}
else
{
return 1;
}
}
function test()
{
if(this->test_empty())
{
return 1;
}
else
{
return 0;
}
}
function test_empty()
{
if(text::test_empty($this->_protected_arr))
{
return 1;
}
else
{
return 0;
}
}
function insert()
{
$url = $this->_protected_arr['url'];
$title = $this->_protected_arr['title'];
$email = $_SESSION['email'];
database::query("INSERT INTO bo VALUES ('$title', '$url', '$email')");
}
}
should not bookmark also create objects from each of its parent classes
That's entirely your choice to make, there is no requirement in the language to call the parent methods.
As the PHP manual concisely puts it:
Note: Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required.
— http://php.net/oop5.decon
While Java will call the no-arg constructor of the parent class if you don't call one specifically, PHP has no such feature. This allows you to do some work before calling the parent constructor, though you obviously shouldn't depend on any properties set by the parent constructor. ;)
BTW, as I stated in a comment, most of your calls that use self:: should be using $this-> instead. Only static methods are called using self::.
In the following code, I have to use $module = $this->uri->segment(4);, table = "omc_".$module; and $id = $this->uri->segment(5); in every function in this class.
How can I avoiding this repetition?
Thanks in advance.
class Admin extends Shop_Admin_Controller {
function Admin(){
parent::Shop_Admin_Controller();
}
function changeStatus(){
$module = $this->uri->segment(4);
$table = "omc_".$module;
$id = $this->uri->segment(5);
if($id && $table){
$this->MKaimonokago->changeStatus($table,$id);
}
flashMsg('success',$this->lang->line('kaimonokago_status_changed'));
redirect("$module/admin/index/","refresh");
}
.................
.................
You could simply add then as instance (i.e.: class level) variables with the appropriate visibility (protected or private) and then initialise them within your constructor.
By doing this you wouldn't need to initialise them within each method, and would still have a more convenient naming regime.
For example:
class Admin extends Shop_Admin_Controller {
private $module;
private $table;
private $id;
public function __construct() {
parent::__construct();
// Initialise uri class here, unless this is done
// in the parent constructor.
$this->module = $this->uri->segment(4);
$this->table = "omc_".$module;
$this->id = $this->uri->segment(5);
}
public function changeStatus() {
if($this->id && $this->table) {
...
}
}
}
Incidentally, I'd also recommend setting the appropriate visibility on your methods, unless of course you're targeting PHP 4, in which case replace the "private" with "var" in the above example and remove the visibility properties from the methods.
How about setting them in the constructor?
function Admin(){
parent::Shop_Admin_Controller();
$this->module = $this->uri->segment(4);
$this->table = "omc_" . $this->module;
$this->id = $this->uri->segment(5);
}
They can then be used as e.g. $this->module in the other functions in your class.
This of course presumes that you don't have properties with those names in the parent class. If you do, you use different names.
Maybe set them as protected attributes in your constructor?
class Admin
{
protected $_module;
protected $_table;
protected $_id;
public function __construct()
{
// do something that initializes $this->uri;
$this->_module = $this->uri->segment(4);
$this->_table = 'omc_' . $module;
$this->_id = $this->uri->segment(5);
}
}