If I have a base abstract class like so:
<?php
abstract class Record {
static $table;
public function getRows () {
return getRowsFromTable(static::$table);
}
}
?>
And I want to extend this class like so:
<?php
class User extends Record {
static $table = 'users';
private $name;
?>
Then if I call:
<?php
$user = new User;
$user->getRows();
?>
Internally, getRows() calls and returns getRowsFromTable('users').
But if I were to create another class that also extends Record:
<?php
class House extends Record {
static $table = 'houses';
private $address;
?>
Then that static $table = 'houses'; declaration overrides the Record::$table and, consequently, breaks the User class.
What's happening is, the declaration static $table = 'houses'; bubbles up to the parent class, so now Record::$table = 'houses';. Since House was declared after User, the next time I call $user->getRows(), internally, User references parent Record and ultimately calls getRowsFromTable('houses') instead of getRowsFromTable('users').
I'm using late static binding so as to get the property from the extended class; but since User and House extend the same parent class, they both end up with the same property value although they override it with different values.
If I were to duplicate the Record class by creating a class Record2 and having House extend Record2, I wouldn't have this problem -- but that wouldn't really help.
Is this the wrong setup? Should I not be using static variables in this context? What should I put in their place, if so? I know that $table doesn't necessarily have to be static, but there are other properties that may need to be static.
I really wouldn't use a static string for this purpose.
How about something like this...
abstract class Record {
/**
* #return table name as string
*/
abstract protected function getTable();
public function getRows () {
return getRowsFromTable($this->getTable());
}
}
Then, your concrete implementations would have to implement getTable, eg
class User extends Record {
protected function getTable() {
return 'users';
}
}
Related
I have a class address_book in which I want to set $DBConnection using method from another class:
<?php
class address_book
{
protected $DBConnection;
public function __construct()
{
$this->DBConnection=new address_book_db();
$this->init();
}
public function init()
{
add_shortcode('address_book', array($this,'load'));
}
public function load()
{
var_dump($DBConnection);
}
}
Another class:
<?php
class address_book_db
{
protected $dbconnection;
public function __construct()
{
$this->dbconnection='1';
}
}
So var_dum should return '1' as it has to be assigned to protected $DBConnection; in the first class. I'm starting my learning of PHP OOP so probably everything is bad.
Any way it has to work like this.
In first class I load db name which is being loaded from another class using methods which determines db name (not developed yet because I just want to pass this constructed dbname to first class).
You're missing $this-> to refer to the class property.
The property's value contains another class, so you have to refer to that class its property as wel with a second ->
var_dump($this->DBConnection->dbconnection)
See the following example (PHP)
class Parent
{
protected $_property;
protected $_anotherP;
public function __construct($var)
{
$this->_property = $var;
$this->someMethod(); #Sets $_anotherP
}
protected function someMethod()
...
}
class Child extends Parent
{
protected $parent;
public function __construct($parent)
{
$this->parent = $parent;
}
private function myMethod()
{
return $this->parent->_anotherP; #Note this line
}
}
I am new to OOP and am a bit ignorant.
Here to access the parents property I am using an instance of that class, which seems wrong :S (no need of being i child then). Is there an easy way, so that i can sync the parent properties with the child properties and can directly access $this->anotherP without having to use $this->parent->anotherP ?
As your Child class is extending your Parent class, every properties and methods that are either public or protected in the Parent class will be seen by the Child class as if they were defined in the Child class -- and the other way arround.
When the Child class extends the Parent class, it can be seen as "Child is a Parent" -- which means the Child has the properties of the Parent, unless it redefines those another way.
(BTW, note that "parent" is a reserved keyword, in PHP -- which means you can't name a class with that name)
Here's a quick example of a "parent" class :
class MyParent {
protected $data;
public function __construct() {
$this->someMethodInTheParentClass();
}
protected function someMethodInTheParentClass() {
$this->data = 123456;
}
}
And it's "child" class :
class Child extends MyParent {
public function __construct() {
parent::__construct();
}
public function getData() {
return $this->data; // will return the $data property
// that's defined in the MyParent class
}
}
That can be used this way :
$a = new Child();
var_dump($a->getData());
And you'll get as output :
int 123456
Which means the $data property, defined in the MyParent class, and initialized in a method of that same MyParent class, is accessible by the Child class as if it were its own.
To make things simple : as the Child "is a" MyParent, it doesn't need to keep a pointer to... itself ;-)
This may save you a few hours of searching around.
Remember: Your Child class only inherits the properties DEFINED in the Parent class... So if you instantiate an object using Parent class and then populate it with data, then this data will NOT be available in your child class...
It's super obvious of course, but I'm guessing others may run into the same issue.
A super simple solution is not to extend anything, simply pass the $object of your parent class into your child class through a constructor. This way you have access to all the properties and methods of the object generated by parent class
Example
class child {
public parentObject;
public function __construct($parentObject) {
$this->parentObject = $parentObject;
}
}
If your $parentObject has a public property $name, then you can access it inside the child class with a function like:
public function print_name() {
echo $this->parentObject->name;
}
Probably a silly question, I have many classes in PHP with this template:
class SomeTable {
private $db;
private $prefix;
private $tbl_name;
function __construct($db, $tbl_name) {
$this->db = $db;
$this->prefix = $db->tblPrefix();
$this->tbl_name = $tbl_name;
$this->install();
}
private function install() {
$sql = "CREATE TABLE IF NOT EXISTS...";
$this->db->query($sql, null);
}
// query functions
...
}
I have one of these classes to represent each table in the database.
The 3 private variables at the top must be available in each class,
and they are set in the constructor.
The constructor is the same for every class.
The install() function is different for every class because it is
used to create the database table. (I like to keep it here because
I can keep looking back at it while I'm writing/editing queries).
Do I then create an abstract class with the 3 variables, constructor, empty install() function and implement it in each class? Will it work the same for me?
I'm sorry if it's a dumb question, I've really never used classes/inheritance before in PHP.
Do I then create an abstract class with the 3 variables, constructor,
empty install() function and implement it in each class? Will it work
the same for me?
Yes. The 3 variables will have to be protected now though, instead of private, since they need to be access from child classes. Something like this:
abstract class DBTable{
protected $db;
protected $prefix;
protected $tbl_name;
function __construct($db, $tbl_name) {
$this->db = $db;
$this->prefix = $db->tblPrefix();
$this->tbl_name = $tbl_name;
}
abstract function install();
}
class SomeTable extends DBTable {
private function install() {
$sql = "CREATE TABLE IF NOT EXISTS...";
$this->db->query($sql, null);
}
}
If you extend a class you will inherit any public or protected methods that exist in the parent class. So if you have a class like so:
class Database {
public function get_database(){
return 'blah';
}
}
And then you extend the class like so:
class Blah extends Database {
...
}
Now, the Blah class will inherit the method get_database() so both Database::get_database() and Blah::get_database() will return the same thing. You can also use the parent:: special name to target the extended class. Note: private methods are only available in the class in which they are instantiated and are not inherited.
I should also note that you can override methods by using the same method name in the child class. So if you write a get_database() method within the Blah class, it will take precedence over the parent's method of the same name.
Having the following class hierarchy:
class TheParent{
public function parse(){
$this->validate();
}
}
class TheChild extends TheParent{
private function validate(){
echo 'Valid!!';
}
}
$child= new TheChild();
$child->parse();
What is the sequence of steps in which this is going to work?
The problem is when I ran that code it gave the following error:
Fatal error: Call to private method TheChild::validate() from context 'TheParent' on line 4
Since TheChild inherits from TheParent shouldn't $this called in parse() be referring to the instance of $child, so validate() will be visible to parse()?
Note:
After doing some research I found that the solution to this problem would either make the validate() function protected according to this comment in the PHP manual, although I don't fully understand why it is working in this case.
The second solution is to create an abstract protected method validate() in the parent and override it in the child (which will be redundant) to the first solution as protected methods of a child can be accessed from the parent?!!
Can someone please explain how the inheritance works in this case?
Other posters already pointed out that the mehods need to be protected in order to access them.
I think you should change one more thing in your code. Your base class parent relies on a method that is defined in a child class. That is bad programming. Change your code like this:
abstract class TheParent{
public function parse(){
$this->validate();
}
abstract function validate();
}
class TheChild extends TheParent{
protected function validate(){
echo 'Valid!!';
}
}
$child= new TheChild();
$child->parse();
creating an abstract function ensures that the child class will definitely have the function validate because all abstract functions of an abstract class must be implemented for inheriting from such a class
Your idea of inheritence is correct, just not the visibility.
Protected can be used by the class and inherited and parent classes, private can only be used in the actual class it was defined.
Private can only be accessed by the class which defines, neither parent nor children classes.
Use protected instead:
class TheParent{
public function parse(){
$this->validate();
}
}
class TheChild extends TheParent{
protected function validate(){
echo 'Valid!!';
}
}
$child= new TheChild();
$child->parse();
FROM PHP DOC
Visibility from other objects
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
Private can only be accessed by the class which defines or Same object type Example
class TheChild {
public function parse(TheChild $new) {
$this->validate();
$new->validate(); // <------------ Calling Private Method of $new
}
private function validate() {
echo 'Valid!!';
}
}
$child = new TheChild();
$child->parse(new TheChild());
Output
Valid!!Valid!!
Hopefully the title made sense and hopefully my question does as well.
So I need to instantiate a Sql class at the start of every page on my site so all other classes can have a valid mysql resource to do queries, updates, etc. without creating multiple Sql objects.
However, currently my classes extend an abstract class for different implementations of functions based on the class context.
Question: In a child of the abstract class, could I use parent::_construct to bypass the abstract superclass and instantiate the Sql class from which the abstract extends?
EX.
class Sql {
function _construct() {
//get valid db resource
}
function query() {
//// query code
}
}
abstract class Display extends Sql {
function show() {
return $this->displayRecipe();
}
abstract function getRecipe();
}
class Members extends Display {
function __construct() {
parent::__construct();
}
function getRecipe($member_id) {
return $this->query("select * from recipes where member=$member_id");
}
}
As you can see I neet to use the function query() of the Sql class which is a granparent class now. However, with the abstract class in the middle, would this throw an exception and break?
Yes it will work:
Class Person{
public $age;
public $name;
public $school;
public function __construct($age,$name,$school){
$this->age = $age;
$this->name = $name;
$this->school = $school;
echo "It works!";
}
}
abstract class Student extends Person{
}
class UniversityStudent extends Student{
public function __construct($age,$name,$shcool){
parent::__construct($age,$name,$school);
}
}
$x = new UniversityStudent(20,"Paul","ULA");
echo $x->age;
The code you posted should work just fine because the constructor in class Members will run the constructor of the parent parent::__construct(), which will run the constructor in Sql because __construct is not being overloaded in class Display.
I hope I explained that well enough, but give it a try :)
Just make sure your construct method has 2 underscores in the Sql class; it only has 1 in the code you posted.