PHP: Классы и объекты (PHP 5) - Manual

downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

The Basics Comparing objects

Last updated: Fri, 26 Jan 2007

view this page in

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

# Введение

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

add a note User Contributed Notes
Классы и объекты (PHP 5)
07-Mar-2007 03:05
`RE: 26-Apr-2006 04:53
<?class_Exists($class)?> call in default <?__autoLoad()?>
better is use <?class_Exists($class,false)?>`
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!)`
phaxius
09-Nov-2006 04:09
`Thanks for the tip Dave, that is a much simpler way to the same functionality. One thing I noticed is that if you want to validate the arguments passed to __construct() but also are using "$this->Args = func_get_args();" to define the class members then you get all or none of the arguments stored as members after validation. For an example, a class that stores a list of numbers may require validation of the arguments to ensure that they are actually numbers before storing this in the object.
Using "$this->Arg = func_get_args();" you could write something like:
<?php
class numbers
{
public function __construct(){
if(func_num_args()>=1){ // if there is at least one argument
for($i=0; $i<func_num_args(); $i++)
{ // validation loop
if(!is_numeric(func_get_arg($i))){ // if not a number
echo 'Invalid argument <br />'; // complain
// return false; // keeps _construct() from defining
} // object members
}
$this->Arg=func_get_args(); // defines object members
} else {die('No arguments passed');} // stops if nothing is
} // passed to _construct()
public function addNums(){
$sum = 0; // place to store the sum, initialized to 0
foreach($this->Arg as $number){ // addition loop
$sum = $sum + $number; // add the previous sum with the
} // value of the current position in the array
return $sum; // returns the final sum
}
public function __destruct(){}
}
$numbers= new numbers(2.3, 7, 62, 3.75, 82, 3, 'n');
foreach($numbers->Arg as $number){
echo $number . '<br />';
}
echo $numbers->addNums() . '<br />';
?>
which would output:
Invalid argument
2.3
7
62
3.75
82
3
n
160.05
Although the sum is correct in this case, the storage of invalid data can cause issues on more complex code, such as if you pass objects in the construction of other objects. If the argument turns out to be an invalid object, and it stores it anyways, some functions involving members of that object will malfunction later. An example of what might happen can be seen if you uncomment the line of code that says "return false;", which would then output:
Invalid argument
Warning: Invalid argument supplied for foreach() in path\filename.php on line 27 Warning: Invalid argument supplied for foreach() in path\filename.php on line 18 0
In this case it results from a lack of member definition within the numbers class itself, but if something is supposed to be an object of a specific type and it is improperly validated then similar messages would result from trying to access the members of that object since it doesn't exist.
As an alternative, one may wish to instead assign default values if something doesn't check out right. That way you can still use the information provided without causing error messages if something is input incorrectly. The code for the alternative constructor could look like:
public function __construct(){
if(func_num_args()>=1){ // if there is at least one argument
for($i=0; $i<func_num_args(); $i++){ // validation loop
if(is_numeric(func_get_arg($i))){ // if the arg is numeric
$nums[$i]=func_get_arg($i); // store it in $nums[$i]
} else {$nums[$i]=0;} // otherwise set to default
$this->Arg[$i]=$nums[$i]; // defines the object members
}
} else {die('No arguments passed');} // stops if nothing is
} // passed to _construct()
which if used would output:
2.3
7
62
3.75
82
3
0
160.05
The invalid data type was set to a default value that is the correct type. One could also add code to clean it up so that it never shows up in the final object.`
DTcorp dot 2004 at gmail dot com
23-Oct-2006 04:22
`It's easy to create a simple emulation of the namespaces or packages support available in java, c++, etc...
<?php
class myPackage {
public function myPublicClassEmu() {
$this->myPrivateClassEmu();
}
private function myPrivateClassEmu() {
$this->myProtectedClassEmu();
}
protected function myProtectedClassEmu() {
function myPrivateFunction() {
echo 'test';
}
return myPrivateFunction();
}
}
$MyPackage = new myPackage(); // or: new myPackage
$MyPackage->myPublicClassEmu();
?>
This will output:
test
Off course this isn't the same as the namespaces in C++, but does provide the same functionality idea`
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.`
seva-php at zend dot com
08-Aug-2006 01:35
`Semi-proxy-patterned multi inheritance simulation example:
<?php
interface INamed
{
public function getName();
}
interface ISon
{
public function getFather();
}
interface IFather
{
public function getSons();
}
abstract class Named implements INamed
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function __destruct()
{}
public function getName()
{
return $this->name;
}
}
abstract class Son implements ISon
{
protected $father;
public function getFather()
{
return $this->father;
}
public function __construct(IFather $father = null)
{
$this->father = $father;
}
public function __destruct()
{}
}
abstract class Father implements IFather
{
protected $sons = array();
public function getSons()
{
return $this->sons;
}
public function __construct($sons = array())
{
$this->sons = $sons;
}
public function __destruct()
{}
}
class Man implements INamed, ISon, IFather
{
public function __construct($name, IFather $father = null, $sons = array())
{
// note: these are just __construct() calls - not real class initializations
Named::__construct($name);
Son::__construct($father);
Father::__construct($sons);
}
public function __destruct()
{
Named::__destruct();
Son::__destruct();
Father::__destruct();
}
public function getFather()
{
return Son::getFather();
}
public function getSons()
{
return Father::getSons();
}
public function getName()
{
return Named::getName();
}
}
$siarhej = new Man('Siaroh', new Man('Adas'), array(new Man('Seva')));
var_dump($siarhej->getName());
var_dump($siarhej->getFather()->getName());
$siarhejSons = $siarhej->getSons();
var_dump($siarhejSons[0]->getName());
?>`
markfarquaad at gmail dot com
04-Aug-2006 02:23
`Variable Object Attributes instead of variable variables:
Actually I figured this out on PHP 4.3, but I'm sure it works on the current PHP 5+:
If you like using variable variables and would like to use the same functionality with attributes of class objects, here's how you can can get a specific attribute of a specific class with variable OBJECTS:
Let's say this is our class:
class Car
{
var $brand;
var $color;
var $year;
function Car()
{
etc...
}
}
Let's say we have an object of Class 'Car', my own car, where $brand = 'Ferrari', $color='red', etc.:
$mycar = new Car();
And another 'Car' object, your car, where $brand='Porsche', $color='black', etc.:
$yourcar = new Car();
Now we need a uniform code snippet to access the color attribute of anyone's 'Car', but we would like to change the object dynamically outside the code delivering the color attribute. Here's how:
The variable or dynamic part is the object (the car owner):
$objectName = 'mycar';
or
$objectName = 'yourcar';
etc...
The static reusable code to deliver the color of any object dynamically is:
$objectAttributeName = 'color';
$objectAttribute = ${$objectName}->$objectAttributeName;
Now:
echo $mycar->color;
will deliver exactly the same as:
echo $objectAttribute
THe difference is, with the dynamic version, you do not have to know $objectName in the static code part, while in the non-variable version you must always specify the object name $mycar, $yourcar, etc to access the obeject's attributes.
I hope this helps anyone who likes reusing code like I do.
Mark`
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.`
25-Apr-2006 07:53
`<?php
if (class_exists("cl_test")) return;
echo "ppppp";
class cl_test{
function cl_test(){
echo "quirky...";
}
} // class definition ends
?>
although the logic is clear php treats the above code differently. PHP translates it to:
class cl_test{
function cl_test(){
echo "quirky...";
}
} // class definition ends
if (class_exists("cl_test")) return;
echo "ppppp";
If you must have the previous logic to work you are forced to have the following code:
if (!class_exists("cl_test")) {
echo "ppppp";
class cl_test{
function cl_test(){
echo "quirky...";
}
} // class definition ends
}`
epeterson5 at student dot gsu dot edu
07-Oct-2005 10:46
`This isn't explicity noted anywhere, I don't think.
If you use a variable after the "->" part of a class attribute call, it will parse the variable as a string to assign/compare that class attribute:
<?php
class User {
var $test;
var $test2;
}
$user1 = new User();
$user2 = new User();
$user1->test = "user1's test";
$user1->test2 = "user1's test2";
$user2->test = "user2's test";
$user2->test2 = "user2's test2";
print_r($user1); print_r($user2);
foreach($user1 as $key => $value)
$user2->$key = $value;
print_r($user1); print_r($user2);
?>
Which outputs:
User Object: user1
[test] => user1's test
[test2] => user1's test2
User Object: user2
[test] => user2's test
[test2] => user2's test2
User Object: user1
[test] => user1's test
[test2] => user1's test2
User Object: user2
[test] => user1's test
[test2] => user1's test2
This is particularly useful when you want to assign a different instance of the same class to $this- I have a standard method that I call when I need to do that:
<?php
function assignToThis($new) {
foreach($new as $key => $value)
$this->$key=$value;
}
?>`
turgut85 at hotmail dot com
29-Jun-2005 06:04
`<?PHP
// How to hold objects in an arrayList and retrieve it //
// Interface implementation //
class Data {
public $Name;
public $Age;
public $Address;
public function __construct($Name,$Age,$Address) {
$this->Name = $Name;
$this->Age = $Age;
$this->Address = $Address;
}
public function __destruct() {
echo "Default Constructor...\n";
}
}
$ArrayList = array();
$ArrayList[0] = new Data("John McDonald","65","Address");
$ArrayList[1] = new Data("Turgut Z. Yesilyurt","30","NJ, USA");
$ArrayList[2] = new Data("Maria ","25","NJ, USA");
print_r($ArrayList);
$obj1 = $ArrayList[1];
echo "Name : ".$obj1->Name."\n";
echo "Age : ".$obj1->Age."\n";
echo "Address : ".$obj1->Address."\n";
// Interface Usage //
interface ShowMe {
public function ShowName();
}
class ShowData implements ShowMe {
public $obj;
public function __construct($Obj) {
$this->obj = $Obj;
$this->ShowName();
}
public function ShowName() {
echo "Age : ".$this->obj->Age."\n";
}
}
echo "\nDisplay Single Data =========================\n\n";
new ShowData($ArrayList[1]);
echo "\n=============================================\n";
// Turgut Z. YESILYURT, MS
// Software Developer //
// NJ, USA //
?>
Array
(
[0] => Data Object
(
[Name] => John McDonald
[Age] => 65
[Address] => Address
)
[1] => Data Object
(
[Name] => Turgut Z. Yesilyurt
[Age] => 30
[Address] => NJ, USA
)
[2] => Data Object
(
[Name] => Maria
[Age] => 25
[Address] => NJ, USA
)
)
Name : Turgut Z. Yesilyurt
Age : 30
Address : NJ, USA
Display Single Data =========================
Age : 30
=============================================
Default Constructor...
Default Constructor...
Default Constructor...`
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)`
bartlewis at gmail dot com
08-Jun-2005 06:29
`In regards to gaehngaehn at hotmail dot com...
More simply, to create an object from a class using a variable, just try the following.
$a = new $class();
Works in php4 and php5.`
S�b.
27-May-2005 09:50
`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 :)`
AJG
16-May-2005 08:13
`[Note from et@php.net:
Your way to create a new, empty, generic object is:
<?php $obj = new stdClass(); ?>
]
I never found a way to create a new, empty, generic object so I coded something up myself. In addition, let me show you some imperfect examples.
<?
// Incorrect:
$obj1 = (object) '';
$obj2 = (object) 0;
$obj3 = (object) 1;
$obj4 = (object) true;
$obj5 = (object) false;
// Syntax error:
$obj6 = (object);
// Correct:
$obj7 = (object) NULL;
?>
The first five ones will work, but will create a 'scalar' field in the object. This is undesirable at best, and can be a real nuisance when doing object automation. For that reason, I now use the following function, which produces a 'clean' object. It's also better semantically, in my opinion.
<?
function object() { return ((object) NULL); }
// Usage:
$object = object();
// Just like:
$array = array();
?>
Please post if you see any problems arising due to this method; thanks. Otherwise enjoy.
--AJG.`
28-Mar-2005 03: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!`
spam at afoyi dot com
20-Mar-2005 05:18
`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()`
farzan at ifarzan dot com
05-Oct-2004 04:04
`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()`"
?>`
add a note
The Basics Comparing objects

Last updated: Fri, 26 Jan 2007
show source | credits | stats | sitemap | contact | advertising | mirror sites
Copyright © 2001-2007 The PHP Group
All rights reserved.
This mirror generously provided by: Yahoo! Inc.
Last updated: Sat Mar 10 10:36:09 2007 PST