PHP面向对象特性

自 PHP 5 起完全重写了对象模型以得到更佳性能和更多特性。本文梳理了一些PHP的面向对象的特性。

1. 类的属性(成员变量)

属性声明是由关键字 public,protected 或者 private 开头,然后跟一个普通的变量声明来组成。其中public在对象中可以直接访问,其他不可以。

属性声明 该类 子类
public ×
protected
private ×

2. static静态属性

声明类属性或方法为静态,就可以不实例化类而直接访问。静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。静态方法或变量不能用thi访问,需要用self来访问。

class A() {
    public static $my_static = 'foo'
    public static function static_func() {
        return self::$my_static;
    }
}
echo A::$my_static;
echo A::static_func();

4.类常量

在类中可以定义一个常量,定义的方法为 const FOO = 'foo'。在访问一个类中的常量是需要用到self关键字。

class A {
    const FOO = 'foo';
    public static function foo() {
        return self::FOO;
    }
}
echo A::FOO;
echo A::foo();

5.构造函数和析构函数

1> 具有构造函数的类每次在创建新的对象时会先调用该构造函数,用此函数可以完成对象的初始化操作。 如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。
Note:与其它方法不同,当 __construct() 被与父类 __construct() 具有不同参数的方法覆盖时,PHP 不会产生一个 E_STRICT 错误信息。

class A {
    public function __construct() {
        echo "A de __construct()";
    }
}
class B extends A {
    public function __construct() {
        parent::__construct();
        echo "B de __construct()";
    }
}
$a = new A();
$b = new B();

2>析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余关闭操作的运行。
Note:析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余关闭操作的运行。

6.抽象类

定义类的关键字abstract,定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。

6.接口类

定义类的关键字interface,使用接口,可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
Note:类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误。

7. 魔术方法

  • __set()
    在给不可访问属性赋值时,__set() 会被调用。
public void __set ( string $name , mixed $value )
  • __get()
    取不可访问属性的值时,__get() 会被调用。
public mixed __get ( string $name )
  • __call()
    当对象调用一个不可访问的方法是,__call方法会被调用
public mixed __call ( string $name , array $arguments )
  • __toString()
    当一个类被当成是字符串时调用该方法。
class Foo {
    public function __toString() {
        return __CLASS__;
    }
}
$foo = new Foo();
echo $foo;
  • __invoke()
    当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
class Foo {
    public function __invoke($param) {
        var_dump($param);
    }
}
$foo = new Foo();
$foo(5);
  • 重载(overloading)使用实例
class PropertyTest {
     /**  被重载的数据保存在此  */
    private $data = array();


     /**  重载不能被用在已经定义的属性  */
    public $declared = 1;

     /**  只有从类外部访问这个属性时,重载才会发生 */
    private $hidden = 2;

    public function __set($name, $value) 
    {
        echo "Setting '$name' to '$value'\n";
        $this->data[$name] = $value;
    }

    public function __get($name) 
    {
        echo "Getting '$name'\n";
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }

        $trace = debug_backtrace();
        trigger_error(
            'Undefined property via __get(): ' . $name .
            ' in ' . $trace[0]['file'] .
            ' on line ' . $trace[0]['line'],
            E_USER_NOTICE);
        return null;
    }

    /**  PHP 5.1.0之后版本 */
    public function __isset($name) 
    {
        echo "Is '$name' set?\n";
        return isset($this->data[$name]);
    }

    /**  PHP 5.1.0之后版本 */
    public function __unset($name) 
    {
        echo "Unsetting '$name'\n";
        unset($this->data[$name]);
    }

    /**  非魔术方法  */
    public function getHidden() 
    {
        return $this->hidden;
    }
}


echo "
\n";

$obj = new PropertyTest;

$obj->a = 1;
echo $obj->a . "\n\n";

var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";

echo $obj->declared . "\n\n";

echo "Let's experiment with the private property named 'hidden':\n";
echo "Privates are visible inside the class, so __get() not used...\n";
echo $obj->getHidden() . "\n";
echo "Privates not visible outside of class, so __get() is used...\n";
echo $obj->hidden . "\n";

你可能感兴趣的:(PHP)