jcastromail at yahoo dot es stated:
****
in php 5.2.0 for classes
$obj1 = $obj2;
is equal to
$obj1 = &$obj2;"
****
However, that is not completely true. While both = and =& will make a variable refer to the same object as the variable being assigned to it, the explicit reference assignment (=&) will keep the two variables joined to each other, whereas the assignment reference (=) will make the assigned variable an independent pointer to the object. An example should make this clearer:
<?php
class z {
public $var = '';
}
$a = new z();
$b =& $a;
$c = $a;
$a->var = null;
var_dump($a);
print '<br>';
var_dump($b);
print '<br>';
var_dump($c);
print '<br><br>';
$a = 2;
var_dump($a);
print '<br>';
var_dump($b);
print '<br>';
var_dump($c);
print '<br><br>';
?>
This outputs:
object(z)#1 (1) { ["var"]=> NULL }
object(z)#1 (1) { ["var"]=> NULL }
object(z)#1 (1) { ["var"]=> NULL }
int(2)
int(2)
object(z)#1 (1) { ["var"]=> NULL }
So although all 3 variables reflect changes in the object, if you reassign one of the variables that were previously joined by reference to a different value, BOTH of those variables will adopt the new value.
Perhaps this is because =& statements join the 2 variable names in the symbol table, whereas = statements applied to objects simply create a new independent entry in the symbol table that simply points to the same location as other entries. I don't know for sure - I don't think this behavior is documented in the PHP manual, so perhaps somebody with more knowledge of PHP's internals can clarify what is going on.
Die Grundlagen
class
Einfache Klassendefinitionen beginnen mit dem Schlüsselwort class, gefolgt von einem Klassennamen, gefolgt von einem Paar geschweifter Klammern, die die Definitionen der Eigenschaften und Methoden der Klasse enthalten.
Der Klassenname kann jeder gültige Bezeichner sein, der kein von PHP reserviertes Wort ist. Ein gültiger Klassenname beginnt mit einem Buchstaben oder einem Unterstrich, gefolgt von einer beliebigen Anzahl von Buchstaben, Ziffern oder Unterstrichen; als regulärer Ausdruck formuliert: [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*.
Eine Klasse darf aus ihren eigenen Konstanten, Variablen ("Eigenschaften" genannt) und Funktionen ("Methoden" genannt) bestehen.
Beispiel #1 Definition einer einfachen Klasse
<?php
class SimpleClass
{
// Deklaration einer Eigenschaft
public $var = 'ein Standardwert';
// Deklaration einer Methode
public function displayVar() {
echo $this->var;
}
}
?>
Die Pseudovariable $this ist verfügbar, falls eine Methode aus einem Objektkontext heraus aufgerufen wird. $this ist eine Referenz auf das aufrufende Objekt (üblicherweise das Objekt, zu dem die Methode gehört, aber möglicherweise ein anderes Objekt, falls die Methode statisch aus dem Kontext eines zusätzlichen Objektes aufgerufen wird).
Beispiel #2 Einige Beispiele für die $this-Pseudovariable
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this ist definiert (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this ist nicht definiert.\n";
}
}
}
class B
{
function bar()
{
// Hinweis: die folgende Zeile führt zu einer Warnung, wenn
// E_STRICT aktiviert ist
A::foo();
}
}
$a = new A();
$a->foo();
// Hinweis: die folgende Zeile führt zu einer Warnung, wenn E_STRICT aktiviert ist
A::foo();
$b = new B();
$b->bar();
// Hinweis: die folgende Zeile führt zu einer Warnung, wenn E_STRICT aktiviert ist
B::bar();
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
$this ist definiert (A) $this ist nicht definiert. $this ist definiert (B) $this ist nicht definiert.
new
Um eine Instanz einer Klasse zu erzeugen, muss das new-Schlüsselwort verwendet werden. Ein Objekt wird immer erzeugt, außer wenn das Objekt einen definierten Konstruktor besitzt, der aufgrund eines Fehlers eine Exception wirft. Klassen sollten vor ihrer Instantiierung definiert werden (in manchen Fällen ist dies eine Notwendigkeit).
Wenn ein string mit dem Namen einer Klasse mit new genutzt wird, wird eine neue Instanz dieser Klasse erzeugt. Falls sich die Klasse in einem Namensraum befindet, muss der vollqualifizierte Name hierfür genutzt werden.
Beispiel #3 Eine Instanz erzeugen
<?php
$instanz = new SimpleClass();
// dies ist auch mit einer Variablen möglich:
$klassenname = 'Foo';
$instanz = new $klassenname(); // Foo()
?>
Im Kontext einer Klasse ist es möglich, neue Objekte mit new self und new parent anzulegen.
Wenn man eine bereits erzeugte Instanz einer Klasse einer neuen Variablen zuweist, wird die neue Variable auf die selbe Instanz zugreifen wie das Objekt, das zugewiesen wurde. Dieses Verhalten ist das selbe, wenn man Instanzen an Funktionen übergibt. Eine Kopie eines bereits erzeugten Objektes erhält man, indem man es klont.
Beispiel #4 Objektzuweisung
<?php
$instanz = new SimpleClass();
$zugewiesen = $instanz;
$referenz =& $instanz;
$instanz->var = '$zugewiesen wird diesen Wert haben';
$instanz = null; // $instanz und $referenz werden null
var_dump($instanz);
var_dump($referenz);
var_dump($zugewiesen);
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$zugewiesen wird diesen Wert haben"
}
Mit PHP 5.3.0 wurden neue Möglichkeiten zur Erzeugung von Instanzen eines Objekts eingeführt:
Beispiel #5 Erzeugen neuer Objekte
<?php
class Test
{
static public function getNew()
{
return new static;
}
}
class Child extends Test
{}
$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);
$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);
$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
bool(true) bool(true) bool(true)
extends
Eine Klasse kann Methoden und Eigenschaften einer anderen Klasse erben, indem man das extends-Schlüsselwort in der Deklaration benutzt. Es ist nicht möglich, mehrere Klassen zu erweitern; eine Klasse kann nur eine einzige Basisklasse beerben.
Die geerbten Methoden und Eigenschaften können durch eine Neudeklaration mit dem gleichen Namen wie in der Elternklasse überschrieben werden. Falls die Elternklasse eine Methode als final definiert hat, kann diese Methode nicht überschrieben werden. Es ist möglich, auf die überschriebenen Methoden oder statischen Eigenschaften zuzugreifen, wenn diese mittels parent:: referenziert werden.
Wenn Methoden überschrieben werden, sollte die Parametersignatur gleich bleiben; andernfalls wird PHP einen E_STRICT-Fehler generieren. Dies gilt nicht für den Konstruktor, der das Überschreiben mit unterschiedlichen Parameter erlaubt.
Beispiel #6 Einfache Vererbung
<?php
class ExtendClass extends SimpleClass
{
// Die Vatermethode überschreiben
function displayVar()
{
echo "Erweiternde Klasse\n";
parent::displayVar();
}
}
$extended = new ExtendClass();
$extended->displayVar();
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
Erweiternde Klasse ein Vorgabewert
Die Grundlagen
09-Jul-2007 01:54
25-Apr-2007 07:42
Classes do not seem to be passed to functions. correctly in PHP4
I'll let you know when I find out why
<?php
class XmlNode
{
var $name;
var $attrs;
var $parentNode;
var $firstChild;
var $nextSibling;
}
function startElement($parser, $name, $attrs)
{
global $XmlRootNode;
global $XmlPreviousSibling;
global $XmlParentNode;
if (is_null($XmlRootNode))
{
$XmlRootNode = new XmlNode;
$currentNode = &$XmlRootNode;
}
else
{
if (is_null($XmlParentNode->firstChild))
{
$XmlParentNode->firstChild = new XmlNode;
$currentNode = &$XmlParentNode->firstChild;
}
else
{
$XmlPreviousSibling->nextSibling = new XmlNode;
$currentNode = &$XmlPreviousSibling->nextSibling;
}
$currentNode->parentNode = &$XmlParentNode;
}
$currentNode->name = $name;
$currentNode->attrs = $attrs;
$XmlPreviousSibling = &$currentNode;
$XmlParentNode = &$currentNode;
echo $XmlParentNode->name;
}
function endElement($parser, $name)
{
global $XmlParentNode;
$XmlParentNode = &$XmlParentNode->parentNode;
}
// nothing wrong with these lines
$file = "vragen.xml";
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, "startElement", "endElement");
if (!($fp = fopen($file, "r"))) die("could not open XML input");
while ($data = fread($fp, 4096)) if (!xml_parse($xml_parser, $data, feof($fp)))
die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser)));
xml_parser_free($xml_parser);
//the xml file should now be converted to xml nodes...
echo $XmlRootNode->name; // returns the name of the root object
echo $XmlRootNode->firstChild; // should return "Object" yet returns nothing.
echo $XmlRootNode->firstChild->name; // shoud return the name of the first object but doesn't
echo $XmlRootNode->firstChild->nextSibling->name; //also returns nothing
?>
14-Dec-2006 09:20
Remember that $this->var and $this->$var are different
when using smth like
<?
class test
{
var $var;
function Setvar()
{
$this->$var = "test";
}
}
$m = new test();
$m->Setvar();
$m->var;
?>
will result in an fatal error or empty var
do instead
<?
$this->var = "test";
?>
then u may access it like <? $m->var; ?>
14-Dec-2006 09:18
Remember that $this->var and $this->$var are different
when using smth like
class test
{
var $var;
function Setvar()
{
$this->$var;
}
}
$m = new test();
$m->Setvar()
$m->var; will result in an fatal error or empty var
29-Nov-2006 04:39
in php 5.2.0 for classes
$obj1 = $obj2;
is equal to
$obj1 = &$obj2;
creating a reference of the object.
<?
class test {
public $var;
}
$instance=new test();
$assigned=new test();
$reference=new test();
$copy=new test();
$instance->var='var of instance';
$assigned->var='var of asigned';
$reference->var='var of reference';
$copy->var='var of copy';
$assigned = $instance;
$reference =& $instance;
$reference->var='var of reference';
echo $instance->var."<br>";
echo $assigned->var."<br>";
echo $reference->var."<br>";
echo $copy->var."<br>";
?>
it's return
var of reference
var of reference
var of reference
var of copy
15-Nov-2006 10:16
The best alternatives I think one has right now to nest a class are:
1- create the nested class in an external file and 'include' that file inside a nesting class function. I prefer to use a static function for this.
2- put the nested class definition in a string inside a nesting class function and use the 'eval' keyword to define the class.
<?php
class MyParent{
public function parentFunction( ){
}
public static function nestedClasses(){
eval('
class MyChild{
function __construct(){
echo "this is a nested class";
}
public function childFunction( )
{
}
}
');
}
}
MyParent::nestedClasses();
$y = new MyChild();
?>
14-Nov-2006 12:09
Note that you cannot nest classes (as of <5.1.2; higher versions are not available yet in my distribution). So, the following
<?php
error_reporting( E_ALL | E_STRICT );
class MyParent
{
public function parentFunction( )
{
}
class MyChild
{
public function childFunction( )
{
}
}
}
$x = new MyParent();
?>
Generates the error "Parse error: syntax error, unexpected T_CLASS, expecting T_FUNCTION in [filename] on line 12". This is contrary to typical OO programming (specifically Java). Hopefully they'll change it sometime soon.
I know in part this is a feature request, but I'm also putting it here in case anyone's looking for information about it: simply, you can't yet do it.
Nicholas
27-Oct-2006 08:00
If E_STRICT is enabled, the first example will generate the following error (and a few others akin to it):
Non-static method A::foo() should not be called statically on line 26
The example should have explicitly declared the methods foo() and bar() as static:
class A
{
static function foo()
{
...
12-Aug-2006 01:29
"Once again, I reiterate, there's no need to overwrite variables and open this can of worms: just make a new variable and be done with it. As long as you don't overwrite variables, it doesn't matter whether or not you use references or assignments (unless you're planning for PHP4 compatibility). "
Always suspect advice that disregards nuanced functionality available to you.
The difference between getting a reference versus a copy is subtle but powerful. It really only became highly relevant to me when I was working in Flash with XML. The nodes from the xml structure were returned as references. So getting a node and changing its value didn't just change the node variable I had, it updated the node within the xml document. Had I only gotten a copy I would have had to have routines for removing and inserting the node in the overall structure.
The moral of this story is that there are times when overwriting variables in a reference is actually very practical and a sign of evovled coding.
Also, there's the old trick of passing an object reference to a function as a parameter so that you can change its properties and not have to return anything. This is particularly useful if you pass more than one object reference to the function, since a function can only ever return one value.
There is a caveat in using references in that so long as one variable within scope is holding a copy of the reference the object will remain in memory.
Please take the time to really learn virtue of references versus copies and decide for yourself whether its a tool that can help you.
13-Apr-2006 09:47
I read the first few comments about references versus assignment on objects, and I still couldn't get it. I'm going to talk about it in terms of practical usage, not the tomfoolery occuring behind the scenes. No talk of memory pointers and the like.
<?php
// prepend this to all examples
class Mushroom
{
public $size;
public function __construct($size) {
$this->size = $size;
}
}
$mushroom = new Mushroom(1);
$assigned_shroom = $mushroom;
$reference_shroom =& $mushroom;
?>
Assignments and references, when it comes down to calling functions and modifying member variables, don't make ANY difference at all.
<?php
$mushroom->size = 5;
// all shrooms are size 5
?>
The only deviation of behavior is when you assign totally new contents to a variable. Usually, this never happens unless you're doing some strange reflection or injection.
<?php
$mushroom = 5;
// mushroom and reference_shroom are the integer 5, assigned_shroom is still a mushroom
?>
<?php
$reference_shroom = 5;
// same effect as example above
?>
<?php
$assigned_shroom = 5;
// only assigned_shroom is an integer
?>
The same would apply for any object type.
Once again, I reiterate, there's no need to overwrite variables and open this can of worms: just make a new variable and be done with it. As long as you don't overwrite variables, it doesn't matter whether or not you use references or assignments (unless you're planning for PHP4 compatibility).
01-Feb-2006 02:40
PHP classes helpfully allow you to define member variables on the fly. On top of that, dynamic variables mean you can create them by name from strings.
This means you can ape the 'Ruby On Rails' view system - or replace heavyweight templating systems like Smarty - with very little code:
view.class.php:
<?
class View
{
public function AddVariables($aVariables){
foreach($aVariables as $name => $value){
$this->AddVariable($name, $value);
}
}
public function AddVariable($name, $value){
$this->$name = $value; // <--- Note the extra $
}
public function Render($template){
include($template . ".php");
// You could put validation in here, so it exits cleanly if the template is missing.
}
protected function AddParagraph($strText){
echo("<p>" . $strText . "</p>");
}
protected function AddOptions($aOptions, $strSelected){
foreach($aOptions as $value => $text){
echo "<option value='" . $value . "'";
if($value==$strSelected){echo " selected";}
echo ">" . $text . "</option>\n";
}
}
}
// The code below would normally be in a calling page/class.
$v = new View();
$v->AddVariables(array("peach"=>"fruit", "carrot"=>"vegetable"));
$v->AddVariables(array("options" => array("1"=>"Jan", "2"=>"Feb", "3"=>"March")));
$v->AddVariable("bodytext", "Some content goes here");
$v->Render("test");
?>
test.php:
<html>
<body>
<p>A peach is a <? echo $this->peach; ?>.</p>
<p>A carrot is a <? echo $this->carrot; ?>.<p>
<form action="#" method="GET">
<select id="test">
<? $this->AddOptions($this->options, 2); ?>
</select>
</form>
<? $this->AddParagraph($this->bodytext); ?>
</body>
</html>
This means you can unleash the awesome power of PHP on your templates, allowing all kinds of cool tricks, while ensuring you're not mixing up your display and business code. You only have access to the variables you pass in there yourself. Oh, and the library of markup rendering member functions you'll create. In PHP.
You can re-use templates - just use the same variables with a different page.
You can swap in different mark-up languages programatically, so you could make versions that spit out HTML, XHTML, WML, and XML for SOAP interfaces.
It's entirely extensible. Either write in more PHP member functions to automate view-based tasks, or derive new classes and extend the functionality that way. (Perfect for your proprietary XML language helper functions - they really don't belong in the same class that's generating XHTML.)
The best part is that it's all PHP, so you don't have to learn a new language (as you would do with Smarty - or if you wanted to switch over to Ruby on Rails.)
Hope someone finds it useful. If anyone makes any improvements, corrections etc. I'd love to see them. :)
You'll need a recent version of PHP5 to run it - some earlier versions gave strange scoping errors with the use of $this. I know that build date 'Jan 11 2006 16:35:21' works.
06-Dec-2005 10:45
PHP 4.3.10:
<?php
class foo {
var $what;
function foo($newWhat = 'foo') {
$this->what = $newWhat;
}
function bar() {
print "<p>I'm a ".$this->what."</p>\n";
}
}
$var = 'foo';
$obj = new $var;
// prints "I'm a foo"
$obj->bar();
$obj = new $var();
// prints "I'm a foo"
$obj->bar();
$obj = new $var('bar');
// prints "I'm a bar"
$obj->bar();
?>
29-Nov-2005 11:10
Note that a function defined in the parent class may not access a private member of a child class.
<?php
class A
{
public function foo() { echo $this->x; }
}
class B extends A
{
protected $x = "class B's member";
}
class C extends A
{
private $x = "class C's member";
}
$b = new B();
$b->foo();
$c = new C();
$c->foo();
// Output:
// class B's member
// Fatal error: Cannot access private property C::$x
?>
In the above example, if you don't want to duplicate function foo() in all of the child classes you would have to make each member foo() operates on protected or public. Effectively breaking encapsulation to in order to implement polymorphism.
10-Oct-2005 07:35
Check this!!!
<?php
class foo{
function bar() {
return $this;
}
function hello() {
echo "Hello";
}
}
$foo = new foo();
$foo->bar()->bar()->bar()->bar()->hello();
?>
Haaa! Rulezzz!
13-Sep-2005 06:32
Note that Class names seem to be case-insensitive in php 5.
eg
class abc
{
..
{
class def extends ABC
{
..
}
works fine.
12-Jun-2005 11:30
Note the little correction on graced's notes below:
Your explanation looks correct about how instances created and destroyed, just wanted to correct some errors in your code below. But Thank you greatly for explaining that I appreciate it.
<?php
$obj1 = new stdclass();
var_dump($obj1); // object #1
$obj1 = new stdclass();
var_dump($obj1); // object #2
// no more references to object #1, so it is destroyed.
$obj1 = new stdclass(); // object #1 (object #2 destroyed right after this expression)
var_dump($obj1);
$obj2 = $obj1; // two variables now reference object #1
$obj1 = new stdclass(); // becomes object #2
var_dump($obj1);
$obj1 = new stdclass(); // object #3
var_dump($obj1);
?>
Output:
object(stdClass)#1 (0) {
}
object(stdClass)#2 (0) {
}
object(stdClass)#1 (0) {
}
object(stdClass)#2 (0) {
}
object(stdClass)#3 (0) {
}
06-Apr-2005 12:22
A very good (in my opinion) change in PHP5 is that objects are always passed by reference. In PHP4 they where passed by value, which cased a copy to be made for every call. (as long as you didn't use "&" of cause)
This example illustrates pass-by-reference, as the name changes in the same object, passed around two different ways:
<?php
class Mother {
private $obj = null;
public function setChild($o) {
$this->obj = $o;
}
public function getChild() {
return $this->obj;
}
}
class Child {
private $name = 'noname';
public function setName($string) {
$this->name = $string;
}
public function getName() {
return $this->name;
}
}
$mom = new Mother();
$frasse = new Child();
$frasse->setName('Johan');
$mom->setChild($frasse);
$frasse->setName('Frans');
print $frasse->getName() . "\n";
print $mom->getChild()->getName() . "\n";
?>
This will print:
Frans
Frans
In PHP4, this would print:
Frans
Johan
29-Mar-2005 08:46
In reponse to jerry's comment: "If you instantiate a class and assign it to a variable over and over again, php will start saving instances #1 and #2 in memory but will stop at these"...
This is because after assigning the new object to the variable, there is no longer anything referencing the old object so it is destroyed. If there WAS another reference, say you assigned another variable to the first variable before setting the first to a new class, it'd be preserved.
In reality, this really makes no difference to the programmer, just thought an explanation was in order.
<?php
$obj1 = new stdclass();
var_dump($obj1); // object #1
$obj1 = new stdclass();
var_dump($obj1); // object #2
// no more references to object #1, so it is destroyed.
$obj1 = new stdclass(); // object #1
var_dump($obj1);
$obj2 = $obj1; // two variables now reference object #1
$obj1 = new stdclass(); // becomes object #3
// no more references to object #2, so it is destroyed
var_dump($obj1);
$obj1 = new stdclass(); // object #2
//etc.
?>
01-Mar-2005 01:08
Objects are not being passed by reference as varables do. Let me try to explain:
Variable passing by reference means that two variables are being binded together, so that changing one variable leads to changes in the other. In fact, there is only one variable.
Object passing by reference is a bit different. It means that not the object itself is being passed (that would lead to copying it and all evil), but only reference to the object is being passed. Now, both VARIABLES point to the same object, BUT they DO NOT point to each other. There are TWO DIFFERENT variables. This means that if you change one VARIABLE, second one would still point to the same object.
So, adding reference operator still has some sense. Here is an example:
<?php
class sampleClass {
public $id;
public function __construct($id) { $this->id=$id; }
}
$object1 = new sampleClass(1);
$object2 = $object1;
echo $object1->id; // 1
echo $object2->id; // 1
$object2 = new sampleClass(2);
echo $object1->id; // 1 So, $object1 was not changed. It still links
// to the same object
echo $object2->id; // 2
$object3 = &$object1; // note the reference operator
$object3 = new sampleClass(3);
echo $object1->id; // 3 This time $object one was changed since it
// was bound with $object3
echo $object2->id; // 2
echo $object3->id; // 3
?>
12-Jan-2005 07:41
If you instantiate a class and assign it to a variable over and over again, php will start saving instances #1 and #2 in memory but will stop at these, and will not save more than those instances(ie. #3, #4, #5, #6...). Instead it will toggle between #1 and #2.
<?php
$obj1 = new stdclass();
var_dump($obj1);
$obj1 = new stdclass();
var_dump($obj1);
$obj1 = new stdclass();
var_dump($obj1);
$obj1 = new stdclass();
var_dump($obj1);
$obj1 = new stdclass();
var_dump($obj1);
$obj1 = new stdclass();
var_dump($obj1);
$obj1 = new stdclass();
var_dump($obj1);
?>
13-Dec-2004 05:36
"Actually, the new variable will access a COPY of the instance and not the SAME instance. This is shown by the example: var_dump($assigned) was not NULLified because a COPY of the instance was assigned to $assigned..."
This is actually incorrect. However, it is explained really poorly in the article.
$instance = new SimpleClass();
This creates the new SimpleClass Object location in the memory. (This spot in memory stores all of the variable and the code to execute.)Then, it points the variable $instance to that location in the memory.
$assigned =$instance;
This takes the location that $instance is pointed to and points the variable $assigned to it as well.
$reference =& $instance;
This line of code points $refrence to the memory spot which contains the location of the SimpleClass object, not the object!
$instance->var = '$assigned will have this value';
This changes the values stored in SimpleClass Object's memory. Since $assigned points to this location as well, $assinged>var is the same value.
$instance = null;
This tells instance to point at nothing. So, it breaks its link to the SimpleClass object. $refrence points to $instance still, but since $instance points to nothing $refrence will also point to nothing.
I know this is kind of tough to understand, so I made an animated gif showing the steps.
http://www.prism.gatech.edu/~gtg624r/Code_Explenation.gif