|
|
Глава 19. Классы и объекты (PHP 5)
В PHP 5 новая объектная модель. Управление объектами PHP полностью переписано,
более удобное и содержит новые возможности.
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
final class FAKE_ENUM_DAY {
const MONDAY = 1;
const TUESDAY = 2;
const WEDNESDAY = 4;
const THURSDAY = 8;
const FRIDAY = 16;
}
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;
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(isset($this->options[$i])){
$this->option = $i;
$this->value = $this->options[$i];
}else{
throw new Exception('Invalid day name!');
}
}
}
public static function compare(REAL_ENUM_DAY $day1, REAL_ENUM_DAY $day2){
return ($day1->day() === $day2->day());
}
public function day(){
return $this->value;
}
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!');
}
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);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->on(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 />';echo new Meeting(new Person('Esra'), new Place('Paris')
, new REAL_ENUM_DAY('TUESDAY')).'.<br />';echo new Meeting(new Person('Mehmed'), new Place('Istanbul')
, new REAL_ENUM_DAY(REAL_ENUM_DAY::SUNDAY)).'.<br />';echo new Meeting(new Person('Yaman'), new Place('Aksaray')
, 8).'.<br />';?>
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;
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)
{
}
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;
echo $world->country('us')->city('seattle')->population('employed');
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();
?>
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();
?>
So it's always the best choice to use the __construct style! (at least if you're running PHP5)
|