Web студия "GrandView"
  Главная   Написать Контакты
   
   
О проекте
Руководство php
 

Глава 19. Классы и объекты (PHP 5)

Введение

В PHP 5 новая объектная модель. Управление объектами PHP полностью переписано, более удобное и содержит новые возможности.



The Basics> <Comparing objects
Last updated: Fri, 26 Jan 2007
 
add a note add a note User Contributed Notes
Классы и объекты (PHP 5)
unclesam at yourshowcase dot com
25-Oct-2007 10:57
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
hyponiq at gmail dot com
11-Oct-2007 07:53
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.";
        }
    }
}
muratyaman at gmail dot com
04-Oct-2007 07:22
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!<br>';
}
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
?>
Aouie Web_Form_Aouie.net
27-Aug-2007 08:02
(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( );
bearachute at gmail dot com
26-Aug-2007 08:53
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);

?>
openspecies
15-Mar-2007 06:14
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 at touchmypixel dot com
14-Feb-2007 09:05
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!)
osculabond at gmail dot com
06-Oct-2006 11:20
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
devoid at digital-ritual dot net
08-Sep-2006 01:41
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.
01-May-2006 06: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.
zabmilenko at hotmail dot com
27-Jun-2005 12:27
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.
Obeliks
10-Jun-2005 02:56
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)
S
Новости
11 июля 2007
Сайт запущен
© 2007 info@grandviewstudio.com
решетки на вентиляторы ; В нашем сервисе можно без проблем купить шикарные заказать свадебный букет по приятным расценкам Z058440144362 Z348613067571