Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Language Reference : Classes and Objects (PHP 5)

Code Examples / Notes » language.oop5

hyponiq

You know, it would be rather nice to have something like:
namespace SomeClassContainer
{
class MyClass1
{
class MyClass1ChildClass
{
function __construct()
{
print "I will print when " . __CLASS__ . " is instanciated, but will only work if " . parent . " is instanciated, also.\n";
print "The syntax would be something like this:\n";
print '    $ns = SomeClassContainer;' . "\n";
print '    $myClass1 = new $ns->MyClass1();' . "\n";
print '    $mySubClass1 = new $myClass1->MyClass1ChildClass();' . "\n";
print "--OR--\n";
print '    $mySubClass1 = new SomeClassContainer::MyClass1::MyClass1ChildClass();' . "\n";
}
}

function __construct()
{
print "I will print when " . __CLASS__ . " is instanciated.";
}
}
}


obeliks

You can call parent::__construct(), even if the class yours inherits from uses the old constructor style "Classname()".
Example:
<?php
class A {
 function A() {
   echo 'Constructor of A<br/>';
 }
}
class B extends A {
 function __construct() {
   parent::__construct();
   echo 'Constructor of B<br/>';
 }
}
class C extends A {
 function __construct() {
   parent::A();
   echo 'Constructor of C<br/>';
 }
}
$b = new B();
echo '<br/>';
$c = new C();
/* will output:
Constructor of A
Constructor of B
Constructor of A
Constructor of C
*/
?>
So you see you can also call parent::Classname() if your superclass uses this format. Keep in mind that it doesn't work the other way round though:
<?php
class A {
 function __construct() {
   echo 'Constructor of A<br/>';
 }
}
class B extends A {
 function __construct() {
   parent::A();
   echo 'Constructor of B<br/>';
 }
}
$b = new B();
/* will output:
Fatal error: Call to undefined method A::a() in __FILE__ on line __LINE__
*/
?>
So it's always the best choice to use the __construct style! (at least if you're running PHP5)


spam

You can call a function defined in an inherited class from the parent class. This works in both PHP 4.3.6 and 5.0.0:
<?php
class p {

function p() {
print "Parent's constructor\n";
}

function p_test() {
print "p_test()\n";
$this->c_test();
}
}
class c extends p {

function c() {
print "Child's constructor\n";
parent::p();
}

function c_test() {
print "c_test()\n";
}
}
$obj = new c;
$obj->p_test();
?>
Outputs:
Child's constructor
Parent's constructor
p_test()
c_test()


séb.

We can't create easily anonymous objects like in JavaScript.
JS example :
   var o = {
       aProperty : "value",
       anotherProperty : [ "element 1", "element 2" ] } ;
   alert(o.anotherProperty[1]) ; // "element 2"
So I have created a class Object :
   class Object {
       function __construct( ) {
           $n = func_num_args( ) ;
           for ( $i = 0 ; $i < $n ; $i += 2 ) {
               $this->{func_get_arg($i)} = func_get_arg($i + 1) ;
           }
       }
   }
   $o = new Object(
       'aProperty', 'value',
       'anotherProperty', array('element 1', 'element 2')) ;
   echo $o->anotherProperty[1] ; // "element 2"
You must feel free to make it better :)


29-mar-2005 12:21

There are 3 simple, and utterly annoying problems with your classes (not because of how you want them to work, but because how the Zend II engine handles them):
1) You cannot type hint string or int/integer in a method signature. This is incredibly annoying that the Zend II engine doesn't support it, but there are workarounds.
2) Supplying null in a method signature for a default value means that you will not accept any null value for that parameter. (therefore the method doesn't need to check if the parameters are null anyway).
3) Sadly, overriding methods is only possible with the Zend II engine via Inheritance or Polymorphism, ( and __construct() can only be defined within a class). If you want to override a method in the same class, my suggestion is to provide the method signature with a $flag = null variable, which you call a SWITCH on to pick what the data should do.
==============================================
Other than the afformentioned, the Zend II engine works very similarly to Java, which has made PHP much more versatile and robust in version 5. Thank you again Zend!


muratyaman

Subject: TYPE HINTING, ENUMS, READABILITY
Uses: REFLECTION, MAGIC FUNCTIONS, EXCEPTIONS, ARRAYS.
<?php
/**
* Natural definition in PHP, similar to an ENUM definition
*/
final class FAKE_ENUM_DAY {
const MONDAY = 1;
const TUESDAY = 2;
const WEDNESDAY = 4;
const THURSDAY = 8;
const FRIDAY = 16;
}
/**
* Better definition of an ENUM
*/
class REAL_ENUM_DAY
{
const MONDAY = 1;
const TUESDAY = 2;
const WEDNESDAY = 4;
const THURSDAY = 8;
const FRIDAY = 16;

private $option;
private $value;
private $options;
/**
* Constructor
* @param string/int $option_or_value
* If input is string
*/
function __construct($option_or_value){
$ref = new ReflectionClass('REAL_ENUM_DAY');
$this->options = $ref->getConstants();
$i = $option_or_value;
if(is_int($i)){
$option = array_search($i, $this->options);
if(isset($this->options[$option])){
$this->option = $option;
$this->value = $this->options[$option];
}else{
throw new Exception('Invalid day index!');
}
}else{//if(is_string($i)){
if(isset($this->options[$i])){
$this->option = $i;
$this->value = $this->options[$i];
}else{
throw new Exception('Invalid day name!');
}
}
}
/**
* Proper comparison function for the class
*/
public static function compare(REAL_ENUM_DAY $day1, REAL_ENUM_DAY $day2){
return ($day1->day() === $day2->day());
}
public function day(){
return $this->value;
}
/**
* More flexible comparison
*/
public function on($when){
if(is_int($when))
return ($this->value === $when);
elseif($when instanceof self)
return ($this->value === $when->day());
else
throw new Exception('Invalid input!');
}
/**
* Handy function to use enum class as string
*/
public function __toString(){
return ucfirst(strtolower($this->option));
}

}
class Person{
public $name;
function __construct($name){
$this->name = $name;
}
}
class Place{
public $name;
function __construct($name){
$this->name = $name;
}
}
function meet(Person $who, Place $where, FAKE_ENUM_DAY $when){
return 'This will not be successful!
';
}
echo meet(new Person('Murat'), new Place('London')
, FAKE_ENUM_DAY::MONDAY);//PHP: INVALID ARGUMENT TYPE
/**
* MUST HAVE FEATURE OF ENUMS:
* 1. .. TO BE USED AS PARAMETER TYPES
* HENCE, RESTRICT THE PARAMETER VALUES
* 2. .. TO MAKE THE CODE MORE READABLE WHILE WRITING IT
*/
class Meeting{
private $who;
private $where;
private $when;
function __construct(Person $who, Place $where, REAL_ENUM_DAY $when){
$this->who = $who;
$this->where = $where;
$this->when = $when;
//if($when === REAL_ENUM_DAY::TUESDAY){//WON'T WORK
if($when->on(REAL_ENUM_DAY::TUESDAY)){//WORKS
//if($when.'' === ''.new REAL_ENUM_DAY('TUESDAY')){//WORKS
//if(REAL_ENUM_DAY::compare($when, new REAL_ENUM_DAY(REAL_ENUM_DAY::TUESDAY))){
throw new Exception("$this->when is not good :(");
}
}
function __toString(){
return "Meeting {$this->who->name} in {$this->where->name} on {$this->when}";
}
}
echo new Meeting(new Person('Murat'), new Place('London')
, new REAL_ENUM_DAY(REAL_ENUM_DAY::MONDAY)).'.<br />';//WORKS
echo new Meeting(new Person('Esra'), new Place('Paris')
, new REAL_ENUM_DAY('TUESDAY')).'.<br />';//CUSTOME EXCEPTION
echo new Meeting(new Person('Mehmed'), new Place('Istanbul')
, new REAL_ENUM_DAY(REAL_ENUM_DAY::SUNDAY)).'.<br />';//PHP: UNDEFINED CONSTANT
echo new Meeting(new Person('Yaman'), new Place('Aksaray')
, 8).'.<br />';//PHP: INVALID ARGUMENT TYPE
?>


farzan

PHP 5 is very very flexible in accessing member variables and member functions. These access methods maybe look unusual and unnecessary at first glance; but they are very useful sometimes; specially when you work with SimpleXML classes and objects. I have posted a similar comment in SimpleXML function reference section, but this one is more comprehensive.
I use the following class as reference for all examples:
<?
class Foo {
   public $aMemberVar = 'aMemberVar Member Variable';
   public $aFuncName = 'aMemberFunc';
   
   
   function aMemberFunc() {
       print 'Inside `aMemberFunc()`';
   }
}
$foo = new Foo;
?>
You can access member variables in an object using another variable as name:
<?
$element = 'aMemberVar';
print $foo->$element; // prints "aMemberVar Member Variable"
?>
or use functions:
<?
function getVarName()
{ return 'aMemberVar'; }
print $foo->{getVarName()}; // prints "aMemberVar Member Variable"
?>
Important Note: You must surround function name with { and } or PHP would think you are calling a member function of object "foo".
you can use a constant or literal as well:
<?
define(MY_CONSTANT, 'aMemberVar');
print $foo->{MY_CONSTANT}; // Prints "aMemberVar Member Variable"
print $foo->{'aMemberVar'}; // Prints "aMemberVar Member Variable"
?>
You can use members of other objects as well:
<?
print $foo->{$otherObj->var};
print $foo->{$otherObj->func()};
?>
You can use mathods above to access member functions as well:
<?
print $foo->{'aMemberFunc'}(); // Prints "Inside `aMemberFunc()`"
print $foo->{$foo->aFuncName}(); // Prints "Inside `aMemberFunc()`"
?>


01-may-2006 02:06

Members can be added to instances on the fly.
Simply use
$apple= new fruit();
$pear=new fruit();
$apple->color='red';
$pear->smell='sweet';
and $apple only will contain a member (field) color, but $pear only will contain a field smell.
It is not clear however whether members an be added to the class at large on the fly.


bearachute

in addition to mail at touchmypixel dot com:
if methods aren't a concern, a great way to work with anonymous objects is to instantiate stdClass, which is php's base class. word up on the ECMAScript -- this works great with json!
<?php
$foo = new stdClass();
$foo->bar = 'string';
$foo->num = 10;
header('Content-type: application/json');
echo json_encode($foo);
?>


unclesam

I discovered by experimentation (when I found it to be undocumented or mentioned in a forum), that it is possible to use anonymous class names when instantiating an object.
To wit:
class Something {
public $someproperty = "somevalue";
}
...
$class = "Something";
$object = new $class;
echo "{$object->someproperty}\n";
will show:
somevalue


zabmilenko

Dynamic instantiation trick:
<?php
class CITY
{
   private $population;
   public function __construct($cityname)
   {
       // Load some city-specific data
   }
   public function population($demographic = 'all')
   {
       return $this->population[$demographic];
   }
}
class COUNTRY
{
   private $code = null;
   private $cities = array();
   public function __construct($code)
   {
       $this->code = $code;
   }
   public function city($cityname)
   {
      if (!$this->cities[$cityname])
      {
          $this->cities[$cityname] = new CITY($cityname);
      }
      return $this->cities[$cityname];
   }
}
class WORLD
{
  private $countries = array();
  public function country($code = 'us')
  {
      if (!$this->countries[$code])
      {
          $this->countries[$code] = new COUNTRY($code);
      }
      return $this->countries[$code];
  }
}
$world = new WORLD;
// Load the country AND city object
echo $world->country('us')->city('seattle')->population('employed');
// Country US is already loaded, only need to load a new city object.
echo $world->country('us')->city('new york')->population();
?>
This example uses Countries and Cities wrapped around a World object.  You can use any schema you want, however.  Think:  Domain->Subdomain->Node or KINGDOM->PHYLUM->CLASS->ORDER->FAMILY->GENUS->SPECIES
What is happening here is that a private array is storing the class objects.  Only the class objects that are needed are loaded, when they are needed.  You can nest this many many times as needed.
You see that the array is never exposed.  Each function reference will check to see if a new class object is needed and create it if necessary.
This is literally as simple as it looks.  Hope it helps someone out.


openspecies

class enum {
 private $__this = array();
 function __construct()
 {
   $args = func_get_args();
   $i = 0;
   do{
     $this->__this[$args[$i]] = $i;
   } while(count($args) > ++$i);
 }
 public function __get($n){
   return $this->__this[$n];
 }
};
$days = new enum(
     "Sunday",
     "Monday",
     "Tuesday",
     "Wednesday",
     "Thursday",
     "Friday",
     "Saturday"
   );
$today = $days->Thursday;
echo $today;


mail

An addition to the earlier post on creating anonymous objects.
You can make a quick anonmymous object just by using an unset variable as an object.
$foo->bar = "Hello World";
var_dump($foo->bar);
If you want to set it you can just use NULL or an empty string.
$foo = NULL;
$foo->bar = "Hello World";
var_dump($foo->bar);
This is extremely useful if you need to set a variable before using it, for example as a STATIC in a CLASS.
class MyClass {
 static $foo = NULL;
}
//
MyClass::$foo->bar = "Hello World";
You can also just create a NULL object and cast it as OBJECT.
$foo = (object) NULL;
This cannot be used when creating CLASS STATICs though.
You can get some nice functionality out of this by combining some of the earlier examples into a simple function (thanks guys).
function object(){
$o = (object) NULL;
$n = func_num_args( ) ;
for ( $i = 0 ; $i < $n ; $i += 2 ) {
  $o->{func_get_arg($i)} = func_get_arg($i + 1) ;
}
return($o);
}
This lets you create an anonymous object, with variables already set, which is useful for single line creation, for example sending an object through to a function.
function say($obj){
var_dump($obj->message);
}
say(object("message", "Hello World"));
Hope this helps for anyone looking how to create anonymous objects in PHP (anyone from the ECMAScript world - JavaScript or ActionScript!)


devoid

After several hours of trying different patterns I have finally figured out a decent method of emulating the concept of TypeSafe ENUM (Java/C++/etc.) with PHP5. Below is an example from a logging application that I am working on.
<code>
/**
* First we need to define a class to act as our 'type'
*/
final class LogLevel extends Object {
private $lvl;
private $description;

public function __construct($lvl,$desc) {
$this->lvl = $lvl;
$this->description = $desc;
}

public function getDescription() {
return $this->description;
}

public function getLevel() {
return $this->lvl;
}

public static function createLevel($lvl,$desc) {
return new LogLevel($lvl,$desc);
}

public static function getByLevel($lvl) {
if (gettype($lvl) !== 'int') {
throw new InvalidArgumentException();
}

foreach (self::$logLevels as $logLevel) {
$level = $logLevel;
if ($lvl < $logLevel->getLevel()) {
break;
}
}

return $level;
}
}
/**
* Here is the part where I ran into problems. I need to make  
* 'constant-values' for the static 'Enum Array' as you can
* not set a static object-scope variable to the results of
* a function at classload time as you can in Java. Several
* people might consider this 'bad-form' in PHP spec, however
* it is the only way I have found to accomplish this feat.
*/
define('LVL_BASIC', new LogLevel(1,  'BASIC'));
define('LVL_ERROR', new LogLevel(5,  'ERROR'));
define('LVL_WARN',  new LogLevel(10, 'WARN'));
define('LVL_BASIC', new LogLevel(20, 'INFO'));
define('LVL_DEBUG', new LogLevel(50, 'DEBUG'));
</code>
Now we need to add our static 'enum' to the class which acts as our type. This 'Enum' will allow us to get an Enum value by id, description, or any other internal property which is part of your class.
<code>
/**
* Add this line to the LogLevel Class
*/
private static $logLevels = array(LVL_BASIC, LVL_ERROR, LVL_WARN, LVL_INFO, LVL_DEBUG);
</code>

I am sure there is probably a way that I could have accomplished something similar by extending PHP's Array classes however, this seemed a much easier and more abstract approach to the problem.


osculabond

A better way to simulate an enum in php5:
<?php
final class Days {
   const Sunday     = 0x00000001;
   const Monday     = 0x00000010;
   const Tuesday    = 0x00000100;
   const Wednesday = 0x00001000;
   const Thursday  = 0x00010000;
   const Friday    = 0x00100000;
   const Saturday  = 0x01000000;
   const Unknown    = 0x00000000;
   // ensures that this class acts like an enum
   // and that it cannot be instantiated
   private function __construct(){}
}
?>
This will allow you to do things like:
<?php
$day_to_email = Days::Thursday;
if($day_to_email == Days::Wednesday) echo "Wednesday<br />";
if($day_to_email == Days::Thursday) echo "Thursday<br />";
if($day_to_email == Days::Friday) echo "Friday<br />";
?>
Which would output:
Thursday
Or if you wanted to get a little fancier you could also do the following:
<?php
$days_to_email = Days::Monday | Days::Wednesday | Days::Friday;
if($days_to_email & Days::Monday) echo "Monday<br />";
if($days_to_email & Days::Tuesday) echo "Tuesday<br />";
if($days_to_email & Days::Wednesday) echo "Wednesday<br />";
if($days_to_email & Days::Thursday) echo "Thursday<br />";
if($days_to_email & Days::Friday) echo "Friday<br />";
?>
Which would output:
Monday
Wednesday
Friday


aouie web_form_aouie.net

(Repeating the post made under classes for PHP 4 section.)
class casting (type casting to an extended class) workaround. Useful to use functionality in an extended class on an instance of a base class (especially when the BaseClass file needs to be small and the extended class functions are huge). Tested to work on public, protected and private vars in PHP5.
---
class ABaseClass
{
 private $T1;
 protected $T2;
 public $T3;
 public function CopyFrom( )
 {
  // If this class had parents then you will want to implement and use parent::$CopyFrom( ). If not, then private members in the parent class will not be copied.
   return get_object_vars( $this );
 }
 protected function CopyInto( $VarArr )
 {
   // If this class had parents then in order to copy the private values we must implement and use parent::CopyInto( $VarArr ).
   $TempArr = get_class_vars( __CLASS__ );
   foreach( $TempArr as $VarName => $Var1 )
     {
       $this->$VarName = $VarArr[ $VarName ];
     }
   }
}
class AnExtendedClass extends ABaseClass
{
 public function __construct( $theBaseClassInstance )
 {
    $this->CopyInto( $theBaseClassInstance->CopyFrom( ) );
 }
 public function LongFunctionIntheFileWithTheExtendedClass( )
 {
   // Bla Bla Bla
 }
}
---
$BaseInstance = new ABaseClass();
...
$ExtendedInstance = new AnExtendedClass( $BaseInstance );
$ExtendedInstance->LongFunctionIntheFileWithTheExtendedClass( );


Change Language


Follow Navioo On Twitter
Basic syntax
Types
Variables
Constants
Expressions
Operators
Control Structures
Functions
Classes and Objects (PHP 4)
Classes and Objects (PHP 5)
Exceptions
References Explained
eXTReMe Tracker