PHP: Classes and Objects (PHP 4) - Manual
PHP  
downloads | documentation | faq | getting help | mailing lists | | php.net sites | links | my php.net 
search for in the  
<Funkce v prom�nn�chextends>
view the version of this page
Last updated: Thu, 15 Jul 2004

Kapitola 13. Classes and Objects (PHP 4)

class

A class is a collection of variables and functions working with these variables. A class is defined using the following syntax:

<?php
class Cart {
   var
$items// Items in our shopping cart
  
   // Add $num articles of $artnr to the cart
 
  
function add_item($artnr, $num) {
      
$this->items[$artnr] += $num;
   }
  
  
// Take $num articles of $artnr out of the cart
 
  
function remove_item($artnr, $num) {
       if (
$this->items[$artnr] > $num) {
          
$this->items[$artnr] -= $num;
           return
true;
       } else {
           return
false;
       } 
   }
}
?>

This defines a class named Cart that consists of an associative array of articles in the cart and two functions to add and remove items from this cart.

Varov�n�

You can NOT break up a class definition into multiple files, or multiple PHP blocks. The following will not work:

<?php
class test {
?>
<?php
  
function test() {
       print
'OK';
   }
}
?>

The following cautionary notes are valid for PHP 4.

V�straha

The name stdClass is used interally by Zend and is reserved. You cannot have a class named stdClass in PHP.

V�straha

The function names __sleep and __wakeup are magical in PHP classes. You cannot have functions with these names in any of your classes unless you want the magic functionality associated with them. See below for more information.

V�straha

PHP reserves all function names starting with __ as magical. It is recommended that you do not use function names with __ in PHP unless you want some documented magic functionality.

In PHP 4, only constant initializers for var variables are allowed. To initialize variables with non-constant values, you need an initialization function which is called automatically when an object is being constructed from the class. Such a function is called a constructor (see below).

<?php
class Cart {
  
/* None of these will work in PHP 4. */
  
var $todays_date = date("Y-m-d");
   var
$name = $firstname;
   var
$owner = 'Fred ' . 'Jones';
  
/* Arrays containing constant values will, though. */
  
var $items = array("VCR", "TV");
}

/* This is how it should be done. */
class Cart {
   var
$todays_date;
   var
$name;
   var
$owner;
   var
$items = array("VCR", "TV");

   function
Cart() {
      
$this->todays_date = date("Y-m-d");
      
$this->name = $GLOBALS['firstname'];
      
/* etc. . . */
  
}
}
?>

Classes are types, that is, they are blueprints for actual variables. You have to create a variable of the desired type with the new operator.

<?php
$cart
= new Cart;
$cart->add_item("10", 1);

$another_cart = new Cart;
$another_cart->add_item("0815", 3);
?>

This creates the objects $cart and $another_cart, both of the class Cart. The function add_item() of the $cart object is being called to add 1 item of article number 10 to the $cart. 3 items of article number 0815 are being added to $another_cart.

Both, $cart and $another_cart, have functions add_item(), remove_item() and a variable items. These are distinct functions and variables. You can think of the objects as something similar to directories in a filesystem. In a filesystem you can have two different files README.TXT, as long as they are in different directories. Just like with directories where you'll have to type the full pathname in order to reach each file from the toplevel directory, you have to specify the complete name of the function you want to call: In PHP terms, the toplevel directory would be the global namespace, and the pathname separator would be ->. Thus, the names $cart->items and $another_cart->items name two different variables. Note that the variable is named $cart->items, not $cart->$items, that is, a variable name in PHP has only a single dollar sign.

<?php
// correct, single $
$cart->items = array("10" => 1);

// invalid, because $cart->$items becomes $cart->""
$cart->$items = array("10" => 1);

// correct, but may or may not be what was intended:
// $cart->$myvar becomes $cart->items
$myvar = 'items';
$cart->$myvar = array("10" => 1); 
?>

Within a class definition, you do not know under which name the object will be accessible in your program: at the time the Cart class was written, it was unknown that the object will be named $cart or $another_cart later. Thus, you cannot write $cart->items within the Cart class itself. Instead, in order to be able to access it's own functions and variables from within a class, one can use the pseudo-variable $this which can be read as 'my own' or 'current object'. Thus, '$this->items[$artnr] += $num' can be read as 'add $num to the $artnr counter of my own items array' or 'add $num to the $artnr counter of the items array within the current object'.

Pozn�mka: There are some nice functions to handle classes and objects. You might want to take a look at the Class/Object Functions.



add a note add a note User Contributed Notes
Classes and Objects (PHP 4)
email at richardlee dot info
05-Sep-2004 05:11
An example of how to pass an object back into its own class for direct use.

(thisClass.php)

<?php

class thisClass{

   var
$var1;
  
   function
thisClass($value)
       {
$this->var1 = $value;}
      
   function
set_var1($value)
       {
$this->var1 = $value;}
   function
get_var1()
       {return
$this->var1;}
  
   function
showVar()       
       {echo
"<p>var1 = ".$this->var1."</p>";}
  
   function
callShowVar($object)
       {
$object->showVar();}
  
   function
copyObject($object)
       {
$this->var1 = $object->get_var1();}

}

?>

(test.php)
<?php

require_once('class.php');

$thisObject = new thisClass(3);
$thatObject = new thisClass(1);

$thatObject->callShowVar($thisObject); //outputs "var1 = 3"

$thisObject->showVar(); //outputs "var1 = 3"
$thatObject->showVar(); //outputs "var1 = 1"
$thatObject->copyObject($thisObject);
$thatObject->showVar(); //outputs "var1 = 3"

?>
babs at sntteam dot org
31-Aug-2004 02:22
We can't split the class declaration in multiple PHP section but we can exit php tag in a function . ex :

<?
class plop {
   function
plop() {
      
$this->whatever = "bar";
   }
   function
foo() {
      
?>
        <pre>foo returns <?=$this->whatever?></pre>
       <?
  
}
};
$a = new plop;
$a->foo();
?>
will print : foo returns bar

PHP Version 4.3.8-9
bishop
20-Jul-2004 01:04
Say you have a factory method that needs to put data into an object before the constructor is called. This might be necessary, for example, if the factory class establishes a connection to a database and the manufactured object uses that connection in the constructor.

Do something like this:
<?php

function &factory($class /* ... */) {
 
// 1) get an object shell
 
$obj = new stdClass();

 
// 2) "type cast" it to the desired class
 
$tmp = explode(':', serialize($obj));
 
$tmp[1] = strlen($class);
 
$tmp[2] = '"' . $class . '"';
 
$obj = unserialize(implode(':', $tmp));

 
// 3) copy construct the manufacturer into the manufacturee
 
$obj->copyFrom($this);

 
// 4) call the real constructor
 
$args = func_get_args();
 
array_shift($args); // skip the class
 
call_user_func_array(array (&$obj, $class), $args);

  return
$obj;
}

?>

NOTE: The Editor's note in the "simon dot li at hongkong dot com" entry is misleading; it only works because the class names "foo" and "bar" are the same length. In general, you must change the first and second entries in serialized array as done above.

Also NOTE: This typecasting business works if you have a function that takes an arbitrary number of arguments and you want to pass those arbitrary arguments into a constructed class.  You can't just use call_user_func_array() in that case because 'new' is an operator, not a function.
catalin dot ivan at utoronto dot ca
06-Jul-2004 10:50
Regarding defining class variables:

The 'var' statement can NOT take Heredoc definitions, i.e. the "<<<MARKER" stuff (these may be somehow 'dynamic' as per warning above).

You must assign them values within the class constructor if you must use Heredoc.
oran at anonimous dot biu dot ac dot il
16-Jun-2003 05:34
class baseclass {
   function static1() {return "bla";}
   function static2() {return call_user_func(array(__CLASS__,'static1'));}
}

[ Editor's Note: Using the above, rather than below, will allow the static function to call its own generation's version of the method. ]

Unfortunately, inheritance of static methods is a bit problematic in PHP, because in order to use a static method you have to know the exact class it's defined in. This means trouble if you want to use one static function (or a static variable) from within another static function. For example:

class baseclass {
   function static1() {return "bla";}
   function static2() {return baseclass::static1();}
}

Now suppose that you write a class newclass that extends baseclass and redefines static1() to return "foo" instead of "bla" - this change will not be reflected in static2() of newclass. Not good at all.

You could use $this->static1() instead of baseclass::static1() in the definition of static2(), but then static2() will not be a static method. Another idea is to use get_class_name() to get the class name inside static2(), but again you need the $this variable to make this function call.

I found no way to overcome this problem, except to use real functions (not methods) for the purpose of wrapping my static functions. The name of the exact class to use is passed as a parameter to the wrapping function. It looks like this:

function wrapped_static1($clname) {
  if (in_array('static1', get_class_methods($clname)))
   return $clname::static1();
  return baseclass::static1();
}
function wrapped_static2($clname) {
  if (in_array('static2', get_class_methods($clname)))
   return $clname::static2();
  return baseclass::static2();
}

class baseclass {
   function static1() {return "bla";}
   function static2() {return wrapped_static1('baseclass');}
}

Now you can go on using baseclass and writing extension classes for it, using the following rules:
1. Use inheritance with your static functions in the natural way, as you would in C++. The wrapping code given here supports just 1 level of inheritance, but it may be improved to work its way up the inheritance tree using PHP's class functions.
2. When calling a static function, always call it through its wrapper.

For example:

class newclass extends baseclass    // example for rule 1
{
  function static1() {return 'foo';}
}
print static2_wrapper('newclass');  // example for rule 2

This is a little cumbersome, but now when you redefine a static function, you can be sure that any functions that rely on it will be able to use the correct definition.
russ dot taylor at nifty dot com
18-Apr-2003 08:31
It is sometimes useful to register a class instance as a session variable.  This can allow classes and their contained values to persist across multiple pages and/or frames.  Frames which need to use the registered class must be loaded (or reloaded) after the class instance is registered and the class declaration must be included in each file that needs to access the registered class.

i.e.
<?
session_start
();// must have a session, duh...

class foo{//normal class declaration

 
var $bar;

  function
foo(){//normal constructor
  
$this->bar = "a value to share and persist";
  }
}

$vital = new foo;//instance "vital" of object type "foo"

session_register("vital");//register the instance "vital"

//other code as needed

?>

**NOTE: it would be helpful to include the class from an external source so the same declaration could be used everywhere its needed, duh

then simply include the class declaration in any other file and you will have access to the registered class instance.  in a separate frame on the same page you could use ...

<?
session_start
();

class
foo{//same class declaration

 
var $bar;

  function
foo(){//normal constructor
  
$this->bar = "a value to share and persist";
  }
}

echo
$vital->bar;

?>

**NOTE: if you use a frameset you must allow processing time of the session registration or the value will not be available!  You can use any number of methods to trigger the delay, but the session must NOT be started on the second page beforre the variable is registered on the first.  On option is to use an onload statement in the first frames body tag, assuming normal html output...

<html><head></head><body onLoad="parent.frame[1].location.reload();"><!--what ever else you need to output--></body></html>

"frame[1]" assumes a two frame layout with frame[0] containing the values to share and frame[1] requiring those values. thus this, when included in frame[0] will force a reload of frame[1] AFTER the class instance was registered.
mcoakley at netplay dot net
18-Jan-2003 04:47
In response to the comments above and using tomcats example directly... I love scripting languages and I love PHP the most out of them. While most programmers (and editors notes) try to state that PHP is not a true OO language it has what you need to develop good OO programs. Sure some of the really strong structured things aren't there but that is the fun you get with scripted languages. But after reading every comment on this page I think people (and I know I am going to get flamed for this one...) should start to fully understand the principles of OO programming: Encapsulation, Polymorphism and Abstraction.

For those new to those terms:
- Encapsulation is what you get when you can have data and the methods that act on those data in an "encapsulated" entity (object)
- Polymorphism is a property of objects that comes through inheritence that allows methods of the same name to perform different (but similar in purpose) actions
- Abstration provides a mechanism to design effective OO heirarchies by pulling common methods or actions into superclasses and using inheritence to provide functionality

If these principles are understood fully, PHP can be used as a great OO language.  Another common complaint is that PHP doesn't offer private/protected members/methods, I too would like to see these features. One BIG thing to keep in mind while desiging an OO program is that the objects should provide funtionality at the class level. Don't think of objects as individual entities but think of a heirarchy that provides "blackboxes" of code. In otherwords the class names should tell you what the object does and the methods only tell you how to invoke the functionality. You should never be concerned with how the object achieves its functionality.
b dot ruecker at portunity dot de
08-Jul-2001 04:22
If you need a destructor, perhaps it is an idear to simulate it this way with a global Destroy-Function:

<?
function DestroyObject ($name)
{
    
$theobject = &$GLOBALS[$name];
     if (
method_exists ($theobject,"Destroy"))
        
$theobject->Destroy ();
     unset (
$GLOBALS[$name]);
}

class
xyz
{
   var
$somevar;

  
// ### This is the constructor
  
function xyz ()
   {
   }

  
// ### This is the destructor which will be called
  
function Destroy ()
   {
       echo (
"Now we destroy it !");
   }

   function
SomeDo ()
   {
       echo (
"doing something: ".$this->somevar);
   }
}

$example = new xyz;

// .... doing something here
$example->somevar = 3;
$example->SomeDo();

DestroyObject ("example");

// ### Test => should produce an error !
$example->SomeDo ();

?>
sgarner at expio dot co dot nz
19-Feb-2001 02:15
[Editor's note: Remember tha PHP is not a hard core OOP language, and even the ones that are do not always support the unusual vector/array references applied to results from methods.]

It seems there is no way to access the return value of a method (or any function) inline, without assigning it to a variable.

For example:

<?php
class Test
{
  function
blah ()
  {
     return array(
1,2,3);
  }

  function
childTest ()
  {
     return new
Test;
  }
}

$test = new Test;

// This does not work:
$foo = $test->blah()[0];

// Instead have to do:
$temp = $test->blah();
$foo = $temp[0];

// Similarly for objects, cannot do:
$foo = $test->childTest()->blah();

// Instead have to do:
$temp = $test->childTest();
$foo = $temp->blah();

?>
buzz77 at gmx dot net
14-Feb-2001 04:33
You can also store object variables as session variables, so that you don't have to create an object every time the page loads.

Let's see how:
here is my simple class file:

// simple.lib.php
class simple
{
  function dummy
  {
   print "TEST SUCCESSFUL!\n";
  }
}

Then, I create a simple .php which starts a new session and registers the object-variable of the "simple"-class.

// test1.php
require ("simple.lib.php");
session_start();
session_register("CLASSOBJ");
$CLASSOBJ=new simple();

That's all.
In the following .php-files you've only to add the following lines:
require("simple.lib.php");
session_start();

To test out if it works, simply call:
$CLASSOBJ->dummy();
and it will print the message.

I tried it out also with quite huge classes, and it always worked (I think the pointer to the instanciated class is stored and the class object itself won't be deleted if you eg. change to another .php-page)
brice at webprojkt dot com
22-Dec-2000 05:23
Defaulting a function parameter to a variable isn't directly supported, but here's how to get around that:

Suppose you have a class:

class query {
   var $sql;
   var $link;

   function go ($SQLstring = $this->sql)
   {
     return mysql_query($this->sql,$link);
   }
}

This doesn't work.  Here's the workaround:

(function spec):
   function go ($SQLstring)
   {
     if (isset($SQLstring)) { $this->sql = $SQLstring; }
     return mysql_query($this->sql,$this->link);
   }

This may not be the best example of this, but I thought I'd throw this out for you folks ... should allow support of presetting of an object value and then execution of the method on that, or something like query::go("SELECT ...");

Enjoy!

p.s. (in this case query::go wouldn't work because it is coded with $this->link, but if you wanted to just use the default connection, it'd work fine :)
iw at warped dot nu
09-Oct-2000 12:12
Here's a very important reminder to those of you used to Java/C++ object references/pointers. When you send a function arguments which include a class object, PHP will make copies of that object for use inside that function.

This differs from passing a Java reference to an object or passing a C++ pointer to an object. Within the scope of the above-mentioned function, calling class methods of the argument object will only affect the copy that PHP creates. Likewise, when the function itself is completed, the copy of the object you passed ceases to exist.

To emulate Java/C++ functionality of arguments that are objects, you just have to modify the given function's signature from this:

function foo(..., $object, ...)

to this:
function foo(..., &$object, ...)

The ampersand(&) thus signifies that the function should receive a reference to the object, instead of creating a copy of the object.
simon dot li at hongkong dot com
13-Sep-2000 11:15
-------------------------------------------------
[Editor's note: class casting per se is not part of the object/class implementation in PHP, but code like the one in this note can kludge if you need it for very simple cases, more complex ones are left to the imagination of the programmer:
<?php
class foo {
   function
foo($name="foo") {
      
$this->name=$name;
   }
}

class
bar extends foo {
   function
boom() {
       echo
"BOOOM!";
   }
}

$f = new foo();
$temp = explode(":",serialize($f));
$temp[2] = "\"bar\"";
$b = unserialize(implode(":",$temp));

$b->boom();

?>
This forces $b to be an instance of "bar" using an object $f, an instance of "foo"]
-------------------------------------------------


About casting of object, say, i got:

class A extends B {
       function A() {
               $this->B();
       }
       ....
}

$b = new B();
$a = new A();

I wanna have a object of class A with "content" of $b:
$a = (A) $b; // not a valid code,(right?) as for illustration.

<Funkce v prom�nn�chextends>
 Last updated: Thu, 15 Jul 2004
show source | credits | sitemap | contact | advertising | mirror sites 
Copyright © 2001-2004 The PHP Group
All rights reserved.
This unofficial mirror is operated at: /
Last updated: Sun Nov 14 23:09:54 2004 Local time zone must be set--see zic manual page