I have found this the best way to grab a parents variables and such (that I love to set in the constructor, like standardized table names, etc.). I just call the parents constructor in the child constructor, then change variables inside the child constructor that needs to be customized for that class, or just leave it alone to make sure I understand I am using the parents constructor in the child constructor. (it's a good note and practice of mine.).
<?php
class MyParentClass
{
$this->table_one = "my_table";
$this->table_two = "variable_table";
}
class MyChildClass extends MyParentClass
{
public function construct()
{
parent::__construct();
$this->table_two = "newly_defined_table";
}
public function action()
{
$table1 = $this->table_one;
$table2 = $this->table_two;
return $table1 . " - " . $table2;
}
}
$myChildClass = new MyChildClass;
echo $myChildClass->action();
//Displays my_table - newly_defined_table
?>
extends
Много често имаме нужда от класове с променливи и функции подобни на тези от друг съществуващ клас. Всъщност е добра практика да дефинираме общ клас, който да може да се използва във всичките проекти и да адаптираме този клас за специфичните нужди на конкретния проект. За да се улесни това, класовете могат да наследяват други класове. Производният клас има всички променливи и функции на базовия клас (това се нарича 'наследство', въпреки факта, че никой не е умрял), както и тези които са допълнително дефинирани. Не е възможно да изваждате променливи или функции от производен клас, т.е. да премахвате вече дефинирани функции и променливи. Производният клас винаги наследява от един базов клас, т.е. множествено наследяване не се поддържа. Наследяването на класове се осъществява с ключовата дума 'extends' (разширява).
<?php
class Named_Cart extends Cart {
var $owner;
function set_owner ($name) {
$this->owner = $name;
}
}
?>
В горния пример е дефиниран клас Named_Cart, който притежава всички променливи и функции от Cart, плюс допълнителната променлива $owner и допълнителната функция set_owner(). Може да създадете именувана пазарска количка по нормалния начин и да установите или да върнете като резултат името на собственика й. Можете да използвате и функциите на нормалната пазарска количка върху именуваната такава:
<?php
$ncart = new Named_Cart; // Създаване на именувана пазарска количка
$ncart->set_owner("kris"); // Задаване на име на пазарската количка
print $ncart->owner; // извежда името на собственика на пазарската количка
$ncart->add_item("10", 1); // (наследена функционалност от Cart)
?>
Това също така се нарича отношение родител-наследник. Създавате родителски клас и използвате extends, за да създадете нов клас базиран на родителския: дъщерен клас. Можете да използвате този дъщерен клас, за да дефинират друг клас базиран на него.
Забележка: Класовете трябва да бъдат дефинирани преди да бъдат използвани! Ако искате клас Named_Cart да наследи клас Cart, трябва първо да дефинирате клас Cart. Ако искате да създадете друг клас наречен Yellow_named_cart, наследяващ класа Named_Cart, ще трябва първо да дефинирате Named_Cart. Накратко: редът на дефиниране на класовете е важен.
If you have a class that extends an other and both classes have a function with the same name then visibility to both classes should be the same, else you will have a fatal error.
An other interested part in the example bellow is that if visibility of the showName method is private then $this->name() will execute the showName method on class test. If it is public or protected it will execute method showName on class extendTest.
<?php
class test {
public function __construct() {
}
public function name() {
$this->xname('John');
}
private function showName($name) {
echo 'my name in test is '.$name;
}
}
class extendTest extends test {
public function __construct() {
parent::__construct();
}
private function showName($name) {
echo 'my name in extendTest is '.$name;
}
}
$test = new extendTest();
$test->name();
?>
result: my name in test is John
If we change visibility of the showName method to public or protected then the result of the above will be:
my name in extendTest is John
You don't need to include_once the parent class if it's already declared. You do have to load the parent first and then the child.
One thing I figured out after a long time about extending a parent class that, if the child class does not have any construct function, it will use its parent's construct.
for example:
<?php
class Main
{
public $a;
public function __construct()
{
echo '::Parent Class initiated::';
$this -> a = 'we are in the parent class';
}
}
class Child extends Main
{
public function getA()
{
return $this -> a;
}
}
$main = new Main();
$main -> child = new Child;
echo $main -> child -> getA();
//Output - ::Parent Class initiated::::Parent Class initiated::we are in the parent class
?>
However, If we have a constructor in the child class as well:
<?php
class Child extends Main
{
public function __construct()
{
}
public function getA()
{
return $this -> a;
}
}
?>
Then :
<?php
$main = new Main();
$main -> child = new Child;
echo $main -> child -> getA();
// Output - ::Parent Class initiated::
?>
Note that the parent variable 'a' is not inherited by the child class if the constructor from the parent class isnt called.
This behaviour of extension made me waste a lot of my precious time, as I could not understand why some of my child classes were inheriting parent variables and some were not.
Hope this helps someone..
<?php
// what if we want to extend more then one class?
Abstract class ExtensionBridge
{
// array containing all the extended classes
private $_exts = array();
public $_this;
function __construct(){$_this = $this;}
public function addExt($object)
{
$this->_exts[]=$object;
}
public function __get($varname)
{
foreach($this->_exts as $ext)
{
if(property_exists($ext,$varname))
return $ext->$varname;
}
}
public function __call($method,$args)
{
foreach($this->_exts as $ext)
{
if(method_exists($ext,$method))
return call_user_method_array($method,$ext,$args);
}
throw new Exception("This Method {$method} doesn't exists");
}
}
class Ext1{
private $name="";
private $id="";
public function setID($id){$this->id = $id;}
public function setName($name){$this->name = $name;}
public function getID(){return $this->id;}
public function getName(){return $this->name;}
}
class Ext2{
private $address="";
private $country="";
public function setAddress($address){$this->address = $address;}
public function setCountry($country){$this->country = $country;}
public function getAddress(){return $this->address;}
public function getCountry(){return $this->country;}
}
class Extender extends ExtensionBridge
{
function __construct()
{
parent::addExt(new Ext1());
parent::addExt(new Ext2());
}
public function __toString()
{
return $this->getName().', from: '.$this->getCountry();
}
}
$o = new Extender();
$o->setName("fabio");
$o->setCountry("brazil");
echo $o;
?>
don't hesitate to email me, happy coding! ;)
Just a quick example of how PHP will handle a parent calling a function named in both the parent and the child class. You would think it might use the function the way it is defined in the parent, but it does use the function that is defined in the child.
<?php
class One{
function showOne(){
echo 'Function One prints';
}
function hitFunction(){
$this->showOne();
}
}
class Two extends One{
function showOne(){
echo 'Function Two prints';
}
}
$thistwo = new Two;
$thistwo->hitFunction(); //prints "Function Two prints"
?>
If you are using a child-class. Remember to call the constructor of the parent class aswell before you start using it. Otherwise you might get different results then you expected. It is stated in this document, but I got confused by the given example. So, here is my example:
<?php
error_reporting(E_ALL);
class test {
var $var;
function test() {
$this->var = 3;
}
}
class testing extends test {
function testing() {
parent::test();
}
function My_test() {
return $this->var;
}
}
$p = new testing();
echo $p->My_test();
// Returns 3
Just a note: It is possible to have a class inherit from multiple other classes, but only in a one-at-a-time linear hierarchy.
So this works, and C gets A and B functions:
<?php
class A {
public function af() { print 'a';}
public function bark() {print ' arf!';}
}
class B extends A {
public function bf() { print 'b';}
}
class C extends B {
public function cf() { print 'c';}
public function bark() {print ' ahem...'; parent::bark();}
}
$c = new C;
$c->af(); $c->bf(); $c->cf();
print "<br />";
$c->bark();
/**results:**/
//abc
//ahem... arf!
?>
This does NOT work:
<?php
class A {
public function af() { print 'a';}
public function bark() {print ' arf!';}
}
class B {
public function bf() { print 'b';}
}
class C extends B, A /*illegal*/ {
public function cf() { print 'c';}
public function bark() {print ' ahem...'; parent::bark();}
}
$c = new C;
$c->af(); $c->bf(); $c->cf();
print "<br />";
$c->bark();
//Parse Error
?>
Here is a simple idea that I use when I need my abstract classes (the inherited classes) implemented before my functional classes.
<?php
$_CLASSES = array_merge (
glob ("classes/*/*.abstract.php"),
glob ("classes/*/*.class.php")
);
foreach ($_CLASSES AS $_CLASS) {
require ($_CLASS);
}
?>
When declaring a class that relies upon another file ( because it extends the class defined in that file ), you should ALWAYS require_once() that file at the top.
This applies even when planning on looping through and including everything in the folder. Use require_once() in your loop, and at the top of the file that NEEDS the include.
This may seem obvious, but check this scenario. You have a class folder:
+ class
--classA.php
--classB.php
--classC.php
--mainClass.php
Here... classA, classB, classC all extend the mainClass.
If you try to create a function that automatically includes all of the classes in a folder, normally, they are included alphabetically.
When you try to instantiate classC, for example, you will get an error:
"Cannot inherit from undefined class mainClass"
EVEN IF you instantiate the mainClass before you instantiate all of the other classes.
In other words, make sure your primary class is included before all others.
Multiple inheritence is often more trouble than it's worth. For example, you have a class foo that inherits from both class bar and class baz. Classes bar and baz both have a fubar() method. When you create a foo object and call its fubar() method, which fubar() method is called: bar's or baz's?
It seems to me that using aggregate to glue one class's methods and data to another object is a bit like Ruby's fixins, but I could be wrong...
[[Editor's note:
The aggregate_* functions have been dropped, as of PHP 5
-S
]]
It is possible to override a method innherited from a parent class by simply re-defining the method (for those of us who enjoy using abstract classes).
<?php
class A
{
var $foo;
function A()
{
$this->foo = "asdf";
}
function bar()
{
echo $this->foo." : Running in A";
}
}
class B extends A
{
function bar()
{
echo $this->foo." : Running in B";
}
}
$myClass = new B;
$myClass->bar();
?>
Just a simple example about inheritance:
<?php
class a1{
var $a=10;
function a1($a){
$this->a=$a;
}
}
class a2 extends a1{
var $x=11;
function a2($x,$y){
$this->x=$x;
parent::a1($y); // or a1::a1($y) or $this->a1($y)
}
}
class a3 extends a2{
var $q=999;
}
$x=new a3(99,9);
echo $x->a,"<br>",$x->x,"<br> ",$x->q;
?>
The output will be:
9
99
999
Just a quick note to make things more clear : while multiple inheritance is not allowed, several levels of single inheritance ARE ALLOWED indeed. Just test this example :
<?php
class A {
var $name='A';
function disp() {
echo $this->name;
}
}
class B extends A {
var $name='B';
}
class C extends B {
var $name='C';
}
$truc = new C() ;
$truc->disp(); // Will output C
?>
This is especially important to keep in mind while building a huge object hierarchy. for example :
+GenericObject
->+ Person
->->Employee
->+Computer
->->+WorkStation
->->-> PPC
->->-> Intel
->->+Server
->->->LDAPServer
->->->IntranetWebServer
.. and so on. Multiple level hierarchy relationship are possible in a tree-like structure (each child has one and only one parent, except for the root object).
a nice example using extends and multiple classes and constructors.
<?php
class CoreObject {
var $name;
function CoreObject($name){
$this->_constructor($name);
}
function _constructor($name){
$this->name = $name;
}
function show(){
printf("%s::%s\n", $this->get_class(), $this->name);
}
function get_class(){
return get_class($this);
}
}
class Container extends CoreObject{
var $members;
function Container($name){
$this->_constructor($name);
}
function &add(&$ref){
$this->members[] = $ref;
return ($ref);
}
function show(){
parent::show();
foreach($this->members as $item){
$item->show();
}
}
function apply(){
}
}
class Person extends CoreObject{
function Person($name){
$this->_constructor($name);
}
}
class Family extends Container {
var $members;
function Family($name){
$this->_constructor($name);
}
}
echo "<pre>\n";
$family = new Family('my family');
$family->add(new Person('father'));
$family->add(new Person('mother'));
$family->add(new Person('girl'));
$family->add(new Person('boy'));
$family->show();
print_r($family);
?>
[Editor's note: For an alternative to multiple inheritance, see the dynamic binding via object aggregation in the corresponding section of the manual.]
Multiple Inheritance is not supported but it is easy to emulate it:
<?php
class multipleInheritance
{
function callClass($class_to_call)
{
return new $class_to_call();
}
}
class A
{
function insideA()
{
echo "I'm inside A!<br />";
}
}
class B
{
function insideB()
{
echo "I'm inside B!<br />";
}
}
class C extends multipleInheritance
{
function insideC()
{
$a = parent::callClass('A');
$a->insideA();
$b = parent::callClass('B');
$b->insideB();
}
}
$c = new C();
$c->insideC();
?>
---
This will succesfully echo:
I'm inside A!
I'm inside B!
This prints out 'ab'. No need to create a new instance of a, therefor both methods still exists with same name.
<?php
class a {
function samename(){
echo 'a';
}
}
class b extends a{
function samename(){
echo 'b';
}
function b(){
a::samename();
b::samename();
}
}
$test_obj = new b();
?>
Just to clarify something about inheritance. The following code :
<?php
class a
{
function call()
{
$this->toto();
}
function toto()
{
echo('Toto of A');
}
}
class b extends a
{
function toto()
{
echo('Toto of B');
}
}
$b=new b;
$b->call();
?>
...will correctly display "toto of B" (that is, the function declared in the parent is correctly calling the redefined function in the child)
if the class B that extends class A does not have a constuctor function (i.e. a function named B), then the constructor function of A will be used instead, you don't need to make a constructor in B just to call the constructor of A.
For example:
<?php
class A
{
function A()
{
echo "HEY! I'm A!\n";
}
}
class B extends A
{
}
$b = new B();
?>
produces the output:
HEY! I'm A!
Just one thing that may seem obvious but not mentionned in this page is that you need to include/require the file containing the parent class or else you'll get an error:
<?php
require(dirname(__FILE__).'/'.'myParent.php');
// ...
myChild extends myParent {
// ...
}
// ...
?>
