类与对象
在线手册:中文  英文

基本概念

class

每个类的定义都以关键字 class 开头,后面跟着类名,后面跟着一对花括号,里面包含有类的属性与方法的定义。

类名可以是任何非 PHP 保留字的合法标签。一个合法类名以字母或下划线开头,后面跟着若干字母,数字或下划线。以正则表达式表示为:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*

一个类可以包含有属于自己的常量变量(称为“属性”)以及函数(称为“方法”)。

Example #1 简单的类定义

<?php
class SimpleClass
{
    
// property declaration
    
public $var 'a default value';

    
// method declaration
    
public function displayVar() {
        echo 
$this->var;
    }
}
?>

当一个方法在类定义内部被调用时,有一个可用的伪变量 $this$this 是一个到主叫对象的引用(通常是该方法所从属的对象,但如果是从第二个对象静态调用时也可能是另一个对象)。

Example #2 $this 伪变量的示例

<?php
class A
{
    function 
foo()
    {
        if (isset(
$this)) {
            echo 
'$this is defined (';
            echo 
get_class($this);
            echo 
")\n";
        } else {
            echo 
"\$this is not defined.\n";
        }
    }
}

class 
B
{
    function 
bar()
    {
        
// Note: the next line will issue a warning if E_STRICT is enabled.
        
A::foo();
    }
}

$a = new A();
$a->foo();

// Note: the next line will issue a warning if E_STRICT is enabled.
A::foo();
$b = new B();
$b->bar();

// Note: the next line will issue a warning if E_STRICT is enabled.
B::bar();
?>

以上例程会输出:

$this is defined (A)
$this is not defined.
$this is defined (B)
$this is not defined.

new

要创建一个类的实例,必须使用 new 关键字。当创建新对象时该对象总是被赋值,除非该对象定义了构造函数并且在出错时抛出了一个异常。类应在被实例化之前定义(某些情况下则必须这样)。

如果在 new 之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。

Example #3 创建一个实例

<?php
$instance 
= new SimpleClass();

// 也可以这样做:
$className 'Foo';
$instance = new $className(); // Foo()
?>

在类定义内部,可以用 new selfnew parent 创建新对象。

当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用克隆给一个已创建的对象建立一个新实例。

Example #4 对象赋值

<?php

$instance 
= new SimpleClass();

$assigned   =  $instance;
$reference  =& $instance;

$instance->var '$assigned will have this value';

$instance null// $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

以上例程会输出:

NULL
NULL
object(SimpleClass)#1 (1) {
   ["var"]=>
     string(30) "$assigned will have this value"
}

PHP 5.3.0 引进了两个新方法来创建一个对象的实例:

Example #5 创建新对象

<?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);
?>

以上例程会输出:

bool(true)
bool(true)
bool(true)

extends

一个类可以在声明中用 extends 关键字继承另一个类的方法和属性。PHP不支持多重继承,一个类只能继承一个基类。

被继承的方法和属性可以通过用同样的名字重新声明被覆盖。但是如果父类定义方法时使用了 final,则该方法不可被覆盖。可以通过 parent:: 来访问被覆盖的方法或属性。

当覆盖方法时,参数必须保持一致否则 PHP 将发出 E_STRICT 级别的错误信息。但构造函数例外,构造函数可在被覆盖时使用不同的参数。

Example #6 简单的类继承

<?php
class ExtendClass extends SimpleClass
{
    
// Redefine the parent method
    
function displayVar()
    {
        echo 
"Extending class\n";
        
parent::displayVar();
    }
}

$extended = new ExtendClass();
$extended->displayVar();
?>

以上例程会输出:

Extending class
a default value

::class

自 PHP 5.5 起,关键词 class 也可用于类名的解析。使用 ClassName::class 你可以获取一个字符串,包含了类 ClassName 的完全限定名称。这对使用了 命名空间 的类尤其有用。

Example #7 类名的解析

<?php
namespace NS {
    class 
ClassName {
    }
    
    echo 
ClassName::class;
}
?>

以上例程会输出:

NS\ClassName


类与对象
在线手册:中文  英文

用户评论:

php at kingsquare dot nl (2013-05-24 06:34:00)

Just to be clear: the correct way of validating a classname, as stated in the docs is:
$valid = preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $className);
(thanks to salathe@php.net & aharvey@php.net for clearing me up!)

ccheeboon at yahoo dot com (2012-06-11 06:32:35)

there are time we would like an object to self destruct if the initializing argument provided during object creation, dictate the object should exist at all.

<?php
class TestClass
{
    private 
$have_girlfren=false;
    
//
    
private function __construct$have_girlfren )
    {
        echo 
"sixth day<br>
 "
;
         
$this->have_girlfren=$have_girlfren;        
         
$this->existenceRequirement();        
    }
    
//
    
private function existenceRequirement()
    {
        if( 
$this->have_girlfren==false )
        {
        echo 
'i want to die<br>
'
;
        
$this->__destruct();
            
          throw new 
Exception();
        }
    }
    
///////////////////////
    
function __destruct()
    {
        echo 
"i am dead<br>
"
;
    }
    
//////////////////
    
static function getNewInstance$have_girlfren)
    {
        try{
        
$new_obj=new TestClass$have_girlfren);
        return 
$new_obj;
        
        }
        catch(
Exception $e)
        {
            
            unset(
$new_obj);
            echo 
"rest in peace<br>
"
;
            return 
false;
        }    
    }
    
//
    
function gotGirlFren()
    {
        return 
$this->have_girlfren;
    }
}

$test_obj=TestClass::getNewInstancefalse );
if( 
$test_obj )
echo 
"bye test oby closing<br>
"
;
else
echo 
"instance commit suicide<br>
"
;
echo 
"--------------<br>
"
;
echo 
"-the end--";

?>

Manish Gupta (2011-10-22 22:07:14)

Some thing that may be obvious to the seasoned PHP programmer, but may surprise someone coming over from C++:

<?php
class Foo
{
$bar 'Hi There';

public function Print(){
    echo 
$bar;
}
}
?>

Gives an error saying Print used undefined variable. One has to explicitly use (notice the use of <?php $this->bar ?>):

<?php
class Foo
{
$bar 'Hi There';

public function Print(){
    echo 
this->$bar;
}
}
?>

 <?php echo $this->bar?> refers to the class member, while using $bar means using an uninitialized variable in the local context of the member function.

Marcus (2011-02-05 11:00:02)

Here's another simple example.

<?php
// PHP 5

// class definition
class Bear {
    
// define properties
    
public $name;
    public 
$weight;
    public 
$age;
    public 
$sex;
    public 
$colour;

    
// constructor
    
public function __construct() {
        
$this->age 0;
        
$this->weight 100;
    }

    
// define methods
    
public function eat($units) {
        echo 
$this->name." is eating ".$units." units of food... ";
        
$this->weight += $units;
    }

    public function 
run() {
        echo 
$this->name." is running... ";
    }

    public function 
kill() {
        echo 
$this->name." is killing prey... ";
    }

    public function 
sleep() {
        echo 
$this->name." is sleeping... ";
    }
}

// extended class definition
class PolarBear extends Bear {

    
// constructor
    
public function __construct() {
        
parent::__construct();
        
$this->colour "white";
        
$this->weight 600;
    }

    
// define methods
    
public function swim() {
        echo 
$this->name." is swimming... ";
    }
}

?>

Doug (2010-10-07 07:29:10)

What is the difference between  $this  and  self ?

Inside a class definition, $this refers to the current object, while  self  refers to the current class.

It is necessary to refer to a class element using  self ,
and refer to an object element using  $this .
Note also how an object variable must be preceded by a keyword in its definition.

The following example illustrates a few cases:

<?php
class Classy {

const       
STAT 'S' // no dollar sign for constants (they are always static)
static     $stat 'Static' ;
public     
$publ 'Public' ;
private    
$priv 'Private' ;
protected  
$prot 'Protected' ;

function 
__construct( ){  }

public function 
showMe( ){
    print 
'<br> self::STAT: '  .  self::STAT // refer to a (static) constant like this
    
print '<br> self::$stat: ' self::$stat // static variable
    
print '<br>$this->stat: '  $this->stat // legal, but not what you might think: empty result
    
print '<br>$this->publ: '  $this->publ // refer to an object variable like this
    
print '<br>' ;
}
}
$me = new Classy( ) ;
$me->showMe( ) ;

/* Produces this output:
self::STAT: S
self::$stat: Static
$this->stat:
$this->publ: Public
*/
?>

ben dot corne at gmail dot com (2010-04-26 12:35:10)

method calling context aware. By this I mean it will get treated differently while being in a new statement compared to being in a regular call.

Example:
<?php
class Foo {
  private 
$className 'Bar';
  
  public function 
make() {
    return new 
$this->className();
  }
  
  public function 
callClassName() {
   
$this->className();
  }

  public function 
className() {
    echo 
"foo\n";
  }

};

class 
Bar {
  public function 
hello() {
    echo 
"bar\n";
  }
};

$foo = new Foo();
$bar $foo->make();

echo 
"expecting 'bar': ";
$bar->hello();

echo 
"expecting 'foo': ";
$foo->callClassName();
?>

even tough $this->className() is written two times in exactly the same way, the one contained in a new statement gets the className field and the other performs the actual method.

Anonymous (2009-11-06 18:54:48)

It is also simple to get or set a property with a name determined at runtime:

<?php
$e
=new E();
$e->{"foo"} = 1// using a runtime name
// is the same as doing:
// $e->foo = 1;
?>

moty66 at gmail dot com (2009-08-16 07:59:57)

I hope that this will help to understand how to work with static variables inside a class

<?php

class {

    public static 
$foo 'I am foo';
    public 
$bar 'I am bar';
    
    public static function 
getFoo() { echo self::$foo;    }
    public static function 
setFoo() { self::$foo 'I am a new foo'; }
    public function 
getBar() { echo $this->bar;    }            
}

$ob = new a();
a::getFoo();     // output: I am foo    
$ob->getFoo();    // output: I am foo
//a::getBar();     // fatal error: using $this not in object context
$ob->getBar();    // output: I am bar
                // If you keep $bar non static this will work
                // but if bar was static, then var_dump($this->bar) will output null 

// unset($ob);
a::setFoo();    // The same effect as if you called $ob->setFoo(); because $foo is static
$ob = new a();     // This will have no effects on $foo
$ob->getFoo();    // output: I am a new foo 

?>

Regards
Motaz Abuthiab

alex c (2009-08-07 12:17:44)

ok this really basic but I always forget this. I always get an error like:

Fatal error: Call to a member function on a non-object

when i deal with oops

if it were me finding the error i'd search the internet for hours and then it would occur to me, I'm putting my class operator inside a function, but i would define the class in global file.

so like this:
test.php
<?
include(class.php);
$class = new newclassname;

function function1(){
  $class->dofunc();
}
?>

you'll get some die errors and try and do this with function1,

function function1(){
  newclassname::dofunc();
}

but if you're using $this inside your class then you'll get another error on non object

so basically, all you need to do is:

function function1(){
  $class = new newclassname;
  $class->dofunc();
}

or

function function1(){
  global $class;
  $class->dofunc();
}

i know it's simple, but it always gets me!

the_french_cow at hotmail dot com (2009-07-14 06:54:54)

For those of us who are new to inheritance, private functions are not visible in an inherited class. Consider: 

<?php
    
class {
        protected function 
func1() {
            echo(
"I'm func1 in A!<br/>");
        }

        private function 
func2() {
            echo(
"I'm func2 in A!<br/>");
        }
    }
    
    class 
extends {
        public function 
func3() {
            echo(
"I'm func3 in B!<br/>");
            
$this->func1();
            
$this->func2();  // Call to private function from extended class results in a fatal error
        
}
    }
    
    
$b = new B;
    
$b->func3();  // Ends in a fatal error

// OR

    
$b->func1();  // Call to protected function from outside world results in a fatal error
?>

If you want a function to be accessible in class B but not to the outside world, it must be declared as protected.

Notes on stdClass (2009-07-09 15:26:10)

stdClass is the default PHP object. stdClass has no properties, methods or parent. It does not support magic methods, and implements no interfaces.

When you cast a scalar or array as Object, you get an instance of stdClass. You can use stdClass whenever you need a generic object instance.
<?php
// ways of creating stdClass instances
$x = new stdClass;
$y = (object) null;        // same as above
$z = (object) 'a';         // creates property 'scalar' = 'a'
$a = (object) array('property1' => 1'property2' => 'b');
?>

stdClass is NOT a base class! PHP classes do not automatically inherit from any class. All classes are standalone, unless they explicitly extend another class. PHP differs from many object-oriented languages in this respect.
<?php
// CTest does not derive from stdClass
class CTest {
    public 
$property1;
}
$t = new CTest;
var_dump($t instanceof stdClass);            // false
var_dump(is_subclass_of($t'stdClass'));    // false
echo get_class($t) . "\n";                   // 'CTest'
echo get_parent_class($t) . "\n";            // false (no parent)
?>

You cannot define a class named 'stdClass' in your code. That name is already used by the system. You can define a class named 'Object'.

You could define a class that extends stdClass, but you would get no benefit, as stdClass does nothing.

(tested on PHP 5.2.8)

webmaster at oehoeboeroe dot nl (2009-05-03 17:03:11)

If you pass $this by reference and then assign a new value to it, it will not behave as you might expect as illustrated by this example:

<?php
class TestClass
{
    public 
$data;
    
    function 
setData(&$data) {
        
$this->data =& $data
    }

    function 
hasData(&$data) {
        
$saved $data;
        
$data true;
        
$result $this->data === true;
        
$data $saved;
        return 
$result;
    }
    
    function 
isDataOf(&$object) {
        return 
$object->hasData($this);
    }
}

$o1 = new TestClass;
$o2 = new TestClass;
$o1->setData($o2);
$o2->setData($o1);
var_dump($o1->hasData($o2));   // true as expected
var_dump($o2->hasData($o1));   // true as expected
var_dump($o1->isDataOf($o2));  // false even though $o1 is in fact the data of $o2
var_dump($o2->isDataOf($o1));  // false even though $o2 is in fact the data of $o1
?>

You can make this example work by replacing the hasData method with:

<?php 
function hasData(&$data) {
    return 
$data === $this->data;
}
?>

However, although I've not tested this, I've been told that Zend Engine 1, i.e. PHP 4, will choke on the === parameter when comparing recursing objects.

ialsoagree (2009-04-23 20:03:30)

Unfortunately, Arpit's solution creates a new class and leaves the old class inaccessible. If you need access to members of the class you are in you'll be unable to get such access. This can be a huge problem.

However, there is a solution:

<?php
class MyClass {
   public 
$message 'Hello';

   public function 
MyClassFunction() {
       function 
innerFunction(&$this_thing$message null) {
          
$this_thing->message = (!is_null($message)) ? $message $this_thing->message;
          
$this_thing->echo_something();
       }
       
innerFunction($this); // echoes 'Hello'
       
innerFunction($this'<br/>New Message'); // echoes '<br/>New Message'
   
}
   
   public function 
echo_something() {
       echo 
$this->message;
   }
}

$class = new MyClass;
$class->MyClassFunction();
?>

By passing $this as a variable by reference, you can access members of the class and even update them. If you don't want to be able to update them, you can simply pass $this to the function but not as a reference.

Arpit (2009-02-06 06:14:20)

//try this code if you define a new class inside an object method than we can refer to "$class->message"
//unset this instance doesn't affected the previous one 
//it will not report a fatal error

<?php

class MyClass {
   public 
$message 'Hello';

   public function 
MyClassFunction() {
             function 
InnerFunction() {
          
$class = new MyClass;
          
print_r($class);
          echo 
$class->message;
          unset(
$class);//unset this doesn't affected the previous one or we can also use different name $classNew=new MyClass;
       
}
       
innerFunction();
   }
}

$class = new MyClass;
$class->MyClassFunction();
?>

ialsoagree (2009-02-02 16:23:32)

I think it's worth mentioning that if you define a function inside of an object method, that function cannot refer to "$this" - doing so will result in PHP reporting a fatal error:

Fatal error: Using $this when not in object context

<?php
class MyClass {
   public 
$message 'Hello';

   public function 
MyClassFunction() {
       function 
InnerFunction() {
          echo 
$this->message// Reports a fatal error
       
}
       
innerFunction();
   }
}

$class = new MyClass;
$class->MyClassFunction();
?>

This issue cannot be solved by using the Scope Resolution Operator if you're trying to access a variable:

<?php
class MyClass {
   public 
$message 'Hello';

   public function 
MyClassFunction() {
       function 
InnerFunction() {
          echo 
MyClass::message// Reports a fatal error
       
}
       
innerFunction();
   }
}

$class = new MyClass;
$class->MyClassFunction();
?>

Additionally, you can NOT create a public function to access that variable:

<?php
class MyClass {
   public 
$message 'Hello';

   public function 
MyClassFunction() {
       function 
InnerFunction() {
          
MyClass::echoSomething();
       }
       
innerFunction();
   }

   public function 
echoSomething() {
      echo 
$this->message// Reports a fatal error
   
}
}

$class = new MyClass;
$class->MyClassFunction();
?>

Note that in this last case, the error is generated on the line below echoSomething function declaration, not at MyClass::echoSomething();

However, it is worth noting that when called directly, echoSomething works fine:

<?php
class MyClass {
   public 
$message 'Hello';

   public function 
MyClassFunction() {
       function 
InnerFunction() {
          
MyClass::echoSomething();
       }
       
innerFunction();
   }

   public function 
echoSomething() {
      echo 
$this->message// Echoes 'Hello'
   
}
}

$class = new MyClass;
$class->echoSomething();
?>

hugo (@) apres (dot) net (2009-01-16 20:37:22)

A simple approach to Multiple Inheritance

You can give yourself something approaching multiple inheritance with the following class:

<?php

class inheritance{

  var 
$bases = array();

  static function 
error_die$errno$errstr$errfile$errline ) {
    
$backtrace debug_backtrace();
    
$detail $backtrace[4];
    
var_dump$backtrace );
    echo 
'<b>Fatal Error</b>: '.$errstr.' of class <b>'.$detail["class"].'</b> in <b>'.$detail["file"].'</b> on line <b>'.$detail["line"].'</b><br/>';
    die();
  }

  private function 
fatal$text ) {
    
set_error_handler( array( 'inheritance''error_die' ) );
    
trigger_error$textE_USER_ERROR );
    
restore_error_handler();
  }

  function 
__call$name$args ) {
    if( 
$this->bases )
      foreach( 
$this->bases as $base 
        if( 
method_exists$base$name ) )
          return 
$base->$name$args );
    
$this->fatal"Call to undefined method <b>".$name."</b>" );
  }

  function 
__set$name$value ) {
    if( 
$this->bases )
      foreach( 
$this->bases as $base )
        if( 
property_exists$base$name ) ) {
          
$base->$name $value;
          return;
        }
  }
 
  function 
__get$name ) {
    if( 
$this->bases )
      foreach( 
$this->bases as $base )
        if( 
property_exists$base$name ) )
          return 
$base->$name;
  }

  function 
__isset$name ) {
    if( 
$this->bases )
      foreach( 
$this->bases as $base )
        if( 
property_exists$base$name ) )
          return isset( 
$base->$name );
  }

  function 
__unset$name ) {
    if( 
$this->bases )
      foreach( 
$this->bases as $base )
        if( 
property_exists$base$name ) ) {
          unset( 
$base->$name );
          return;
        }
  }

  function 
inherits$name$args '' ) {
    return 
array_unshift$this->bases, new $name$args ) );
  }

}

?>

Most of the qualities of multiple inheritance provided by this class are revealed by the following code:

<?php //test inheritance

class base0 {
  public 
$base0var;
  public 
$basevar;

  function 
base0declare() {
    echo 
'I am base 0';
  }
  function 
basedeclare() {
    
self::base0declare() {
  }
}

class 
base1 extends base0 // simple linear inheritance here
  
public $base1var;
  public 
$basevar;

  function 
based1declare() {
    echo 
'I am base 1';
  }
  function 
basedeclare() {
    
self::base1declare()
  }
}

class 
base2
  
public $base2var;
  public 
$basevar;
  function 
based2declare() {
    echo 
'I am base 2';
  }
  function 
basedeclare() {
    
self::base2declare
  
}
}
?>

Multiple inheritance is achieved by extending the inheritance class, and then in the __construct function placing calls to the "inherits" method of the inheritance class. Each call pushes an instance of the inherited class into an array var which functions as a LIFO stack. Using the magic methods, any failed method call, property set, get, isset or unset is intercepted by the inheritance base class which then attempts to resolve the reference. Object method name conflicts are resolved simply by the later inheritance masking the scope of the earlier inherited method. I recognize there are shortcomings to the approach I offer here, but it works for all my current multiple inheritance needs and offers simplicity and ease of understanding as benefits.

<?php
class base_test extends inheritance // multiple inheritance

  
function __construct() {
    
$this->inherits'base1' );
    
$this->inherits'base2' );
  }

?>

Here are some code fragments you can try out to test things.

<?php

$testobj 
= new base_test();
var_dump$testobj );
$testobj->base2declare();
$testobj->base1declare();
$testobj->base0declare();
$testobj->basedeclare();
$testobj->base2var 27;
echo 
$testobj->base2var;

?>

I'd be interested in hearing any comments.

chris (@) xeneco (dot) co (dot) uk (2008-11-27 03:25:40)

Regarding object inheritance:

I hope this helps someone, it should help if you're new to OOPS

<?php

class {
    
    public 
$x 'A';

    public function 
foo() {
        
$b = new B;
        
$b->bar();
        return 
$this->x;
    }
}

class 
extends {
    public function 
bar() {
        
$this->'B';
    }
}

$a = new A

echo $a->foo();    //A

?>

I was doing something similar to this (example is greatly simplified to show logic) and spent a long while trying to work out why I would always get 'A' and never get 'B'. Now, after a few weeks, I have revisited the problem and have worked out why:

The code 'new B' creates a new instance of class B. While class B extends class A, it is a new object and not an extension of the object created by 'new A'

The value of $x is set to 'B' within the object $b, but not in object $a.

If within A::foo(), one was to access $b->x then one would obtain the vale 'B', for example

<?php

class {
    
    public 
$x 'C';

    public function 
foo() {
        
$c = new C;
        
$c->bar();
        
$this->$c->$x
        
return $this->x;
    }
}

class 
extends {
    public function 
bar() {
        
$this->'D';
    }
}

$c = new C

echo $c->foo();    //D

?>

Jeffrey (2008-10-08 15:49:54)

A PHP Class can be used for several things, but at the most basic level, you'll use classes to "organize and deal with like-minded data". Here's what I mean by "organizing like-minded data". First, start with unorganized data.

<?php
$customer_name
;
$item_name;
$item_price;
$customer_address;
$item_qty;
$item_total;
?>

Now to organize the data into PHP classes:

<?php
class Customer {
  
$name;          // same as $customer_name
  
$address;       // same as $customer_address
}

class 
Item {
  
$name;          // same as $item_name
  
$price;         // same as $item_price
  
$qty;           // same as $item_qty
  
$total;         // same as $item_total
}
?>

Now here's what I mean by "dealing" with the data. Note: The data is already organized, so that in itself makes writing new functions extremely easy.

<?php
class Customer {
  public 
$name$address;                   // the data for this class...

  // function to deal with user-input / validation
  // function to build string for output
  // function to write -> database
  // function to  read <- database
  // etc, etc
}

class 
Item {
  public 
$name$price$qty$total;        // the data for this class...

  // function to calculate total
  // function to format numbers
  // function to deal with user-input / validation
  // function to build string for output
  // function to write -> database
  // function to  read <- database
  // etc, etc
}
?>

Imagination that each function you write only calls the bits of data in that class. Some functions may access all the data, while other functions may only access one piece of data. If each function revolves around the data inside, then you have created a good class.

wbcarts at juno dot com (2008-08-20 18:11:12)

CLASSES and OBJECTS that represent the "Ideal World"

Wouldn't it be great to get the lawn mowed by saying $son->mowLawn()? Assuming the function mowLawn() is defined, and you have a son that doesn't throw errors, the lawn will be mowed. 

In the following example; let objects of type Line3D measure their own length in 3-dimensional space. Why should I or PHP have to provide another method from outside this class to calculate length, when the class itself holds all the neccessary data and has the education to make the calculation for itself?

<?php

/*
 * Point3D.php
 *
 * Represents one locaton or position in 3-dimensional space
 * using an (x, y, z) coordinate system.
 */
class Point3D
{
    public 
$x;
    public 
$y;
    public 
$z;                  // the x coordinate of this Point.

    /*
     * use the x and y variables inherited from Point.php.
     */
    
public function __construct($xCoord=0$yCoord=0$zCoord=0)
    {
        
$this->$xCoord;
    
$this->$yCoord;
        
$this->$zCoord;
    }

    
/*
     * the (String) representation of this Point as "Point3D(x, y, z)".
     */
    
public function __toString()
    {
        return 
'Point3D(x=' $this->', y=' $this->', z=' $this->')';
    }
}

/*
 * Line3D.php
 *
 * Represents one Line in 3-dimensional space using two Point3D objects.
 */
class Line3D
{
    
$start;
    
$end;

    public function 
__construct($xCoord1=0$yCoord1=0$zCoord1=0$xCoord2=1$yCoord2=1$zCoord2=1)
    {
        
$this->start = new Point3D($xCoord1$yCoord1$zCoord1);
        
$this->end = new Point3D($xCoord2$yCoord2$zCoord2);
    }

    
/*
     * calculate the length of this Line in 3-dimensional space.
     */ 
    
public function getLength()
    {
        return 
sqrt(
            
pow($this->start->$this->end->x2) +
            
pow($this->start->$this->end->y2) +
            
pow($this->start->$this->end->z2)
        );
    }

    
/*
     * The (String) representation of this Line as "Line3D[start, end, length]".
     */
    
public function __toString()
    {
        return 
'Line3D[start=' $this->start .
            
', end=' $this->end .
            
', length=' $this->getLength() . ']';
    }
}

/*
 * create and display objects of type Line3D.
 */
echo '<p>' . (new Line3D()) . "</p>\n";
echo 
'<p>' . (new Line3D(0001001000)) . "</p>\n";
echo 
'<p>' . (new Line3D(000100100100)) . "</p>\n";

?>

  <--  The results look like this  -->

Line3D[start=Point3D(x=0, y=0, z=0), end=Point3D(x=1, y=1, z=1), length=1.73205080757]

Line3D[start=Point3D(x=0, y=0, z=0), end=Point3D(x=100, y=100, z=0), length=141.421356237]

Line3D[start=Point3D(x=0, y=0, z=0), end=Point3D(x=100, y=100, z=100), length=173.205080757]

My absolute favorite thing about OOP is that "good" objects keep themselves in check. I mean really, it's the exact same thing in reality... like, if you hire a plumber to fix your kitchen sink, wouldn't you expect him to figure out the best plan of attack? Wouldn't he dislike the fact that you want to control the whole job? Wouldn't you expect him to not give you additional problems? And for god's sake, it is too much to ask that he cleans up before he leaves?

I say, design your classes well, so they can do their jobs uninterrupted... who like bad news? And, if your classes and objects are well defined, educated, and have all the necessary data to work on (like the examples above do), you won't have to micro-manage the whole program from outside of the class. In other words... create an object, and LET IT RIP!

ashraf dot samhouri at hotmail dot com (2008-05-24 06:35:00)

@info -- 20-April
This is because you requested class "b" before defining it, not because you defined class "b" before "a". It doesn't make a difference which class you define first.

info at youwanttoremovethisvakantiebaas dot nl (2008-04-20 15:40:51)

if you do this
<?php

$x 
= new b();

class 
extends {}

class 
{ }

?>
PHP will tell you "class b not found", because you've defined class b before a. However, the error tells you something different.... Got me a little confused :)

david dot schueler at tel-billig dot de (2008-02-15 06:16:57)

If you just want to create a new object that extends another object and you want to copy all variables from the father object, you may use this piece of code:
<?php
$father 
=& new father();
$father->a_var "Hello World.";

$son = new son($event);

$son->say_hello();

class 
father {
    public 
$a_var;
}

class 
son extends father {
    public function 
__construct($father_class) {
        foreach (
$father_class as $variable=>$value) {
            
$this->$variable $value;
        }
    }

    public function 
say_hello() {
        echo 
"Son says: ".$this->a_var;
    }
}
?>
This outputs:

Son says: Hello World.

So you dont have to clone the entire object to get the contents of the variables from the father object.

aaron at thatone dot com (2007-12-15 18:46:09)

I was confused at first about object assignment, because it's not quite the same as normal assignment or assignment by reference. But I think I've figured out what's going on.

First, think of variables in PHP as data slots. Each one is a name that points to a data slot that can hold a value that is one of the basic data types: a number, a string, a boolean, etc. When you create a reference, you are making a second name that points at the same data slot. When you assign one variable to another, you are copying the contents of one data slot to another data slot.

Now, the trick is that object instances are not like the basic data types. They cannot be held in the data slots directly. Instead, an object's "handle" goes in the data slot. This is an identifier that points at one particular instance of an obect. So, the object handle, although not directly visible to the programmer, is one of the basic datatypes. 

What makes this tricky is that when you take a variable which holds an object handle, and you assign it to another variable, that other variable gets a copy of the same object handle. This means that both variables can change the state of the same object instance. But they are not references, so if one of the variables is assigned a new value, it does not affect the other variable.

<?php
// Assignment of an object
Class Object{
   public 
$foo="bar";
};

$objectVar = new Object();
$reference =& $objectVar;
$assignment $objectVar

//
// $objectVar --->+---------+
//                |(handle1)----+
// $reference --->+---------+   |
//                              |
//                +---------+   |
// $assignment -->|(handle1)----+
//                +---------+   |
//                              |
//                              v
//                  Object(1):foo="bar"
//
?>

$assignment has a different data slot from $objectVar, but its data slot holds a handle to the same object. This makes it behave in some ways like a reference. If you use the variable $objectVar to change the state of the Object instance, those changes also show up under $assignment, because it is pointing at that same Object instance.

<?php
$objectVar
->foo "qux";
print_r$objectVar );
print_r$reference );
print_r$assignment );

//
// $objectVar --->+---------+
//                |(handle1)----+
// $reference --->+---------+   |
//                              |
//                +---------+   |
// $assignment -->|(handle1)----+
//                +---------+   |
//                              |
//                              v
//                  Object(1):foo="qux"
//
?>

But it is not exactly the same as a reference. If you null out $objectVar, you replace the handle in its data slot with NULL. This means that $reference, which points at the same data slot, will also be NULL. But $assignment, which is a different data slot, will still hold its copy of the handle to the Object instance, so it will not be NULL.

<?php
$objectVar 
null;
print_r($objectVar);
print_r($reference);
print_r($assignment);

//
// $objectVar --->+---------+
//                |  NULL   | 
// $reference --->+---------+
//                           
//                +---------+
// $assignment -->|(handle1)----+
//                +---------+   |
//                              |
//                              v
//                  Object(1):foo="qux"
?>

alan at alan-ng dot net (2007-10-09 21:41:18)

The following odd behavior happens in php version 5.1.4 (and presumably some other versions) that does not happen in php version 5.2.1 (and possibly other versions > 5.1.4).

<?php

$_SESSION
['instance']=...;

$instance=new SomeClass;

?>

The second line will not only create the $instance object successfully, it will also modify the value of $_SESSION['instance']!

The workaround I arrived at, after trial and error, was to avoid  using object names which match a $_SESSION array key.

This is not intended to be a bug report, since it was apparently fixed by version 5.2.1, so it's just a workaround suggestion.

Dan Dascalescu (2006-10-26 23:00:35)

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()
{
...

易百教程