PHP类与面向对象(二)

构造函数和析构函数

构造函数
PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用parent::__construct()。

class BaseClass {
    function __construct()
    {
        print 'In BaseClass construct<br/>';
    }
}

class SubClass extends BaseClass {
    function __construct()
    {
        parent::__construct();
    }
}

$base = new BaseClass();
$sub = new SubClass();

析构函数
析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。

class MyDestructableClass {
    function __construct()
    {
        print 'in construct<br/>';
        $this->name = 'MyDestructableClass';
    }

    function __destruct()
    {
        // TODO: Implement __destruct() method.
        print 'Destroying ' . $this->name . '<br/>';
    }
}

$obj = new MyDestructableClass();

访问控制
由 public 所定义的类成员可以在任何地方被访问;
由 protected 所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问);
而由 private 定义的类成员则只能被其所在类访问。

class MyClass {
    public $public = 'Public';
    protected $protected = 'Protected';
    private $private = 'Private';

    public function printHello()
    {
        echo $this->public;
        echo '<br>';
        echo $this->protected;
        echo '<br>';
        echo $this->private;
    }
}

/*$obj = new MyClass();
echo $obj->public;
echo '<br>';
$obj->printHello();*/

class MyClass2 extends MyClass {
    // 可以对 public 和 protected 进行重定义,但private不能
    protected $protected = 'Protected2';

    public function printHello()
    {
        parent::printHello(); // TODO: Change the autogenerated stub
    }
}

$obj2 = new MyClass2();
echo $obj2->printHello();

对方法访问的控制

class MyClass {
    // 构造函数必须是 public
    public function __construct()
    {}

    public function MyPublic()
    {}

    protected function MyProtected()
    {}

    private function MyPrivate()
    {}

    public function foo ()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}

$obj = new MyClass();
$obj->MyPublic();
$obj->foo();

class MyClass2 extends MyClass {
    public function foo()
    {
        parent::foo(); // TODO: Change the autogenerated stub
/*        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate(); // 这行会产生一个致命错误*/
    }
}

$obj2 = new MyClass2();
$obj2->foo();

对象继承
当扩展一个类,子类就会继承父类的所有公有和保护方法。但是子类的方法会覆盖父类的方法。

class foo
{
    public function printItem($string)
    {
        echo 'Foo: ' . $string . '<br/>';
    }

    public function printPHP()
    {
        echo 'PHP is great<br/>';
    }
}

class bar extends foo
{
    public function printItem($string)
    {
        echo 'Bar: ' . $string . '<br/>';
    }
}

$bar = new bar();
$bar->printItem('bazz');
$bar->printPHP();

范围解析操作符(::)
用于访问静态成员、方法和常量,或者覆盖类中的成员和方法。
当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。
self 和 parent 这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。

// 在类的外部使用范围解析操作符
class MyClass {
    const CONST_VALUE = 'A constant value';
}

echo MyClass::CONST_VALUE;
class OtherClass extends MyClass {
    public static $my_static = 'static var';

    public static function doubleColon ()
    {
        echo self::$my_static;
        echo '<br/>';
        echo parent::CONST_VALUE;
    }
}

OtherClass::doubleColon();
class MyClass {
    protected function myFunc()
    {
        echo 'MyClass::myFunc()<br/>';
    }
}

class OtherClass extends MyClass {
    public function myFunc()
    {
        parent::myFunc(); // TODO: Change the autogenerated stub
        echo 'OtherClass::myFunc()';
    }
}

$other = new OtherClass();
$other->myFunc();

作业:

// 请定义一个动物类,然后定义一个小狗类继承动物类,里面定义一个吠叫的方法,最后实例化一条小狗,调用它吠叫的方法。
class Animal
{
    public function call()
    {
        echo 'Animal<br/>';
    }
}

class Dog extends Animal
{
    public function call()
    {
        parent::call();
        echo 'wang';
    }
}

$dog = new Dog();
$dog->call();

static关键字
声明类成员或方法为static,就可以不实例化类而直接访问
由于静态方法不需要通过对象即可调用,所以伪变量$this在静态方法中不可用。
静态属性不可以由对象通过->操作符来访问。
用::方式调用一个非静态方法会导致一个E_STRICT级别的错误。
静态属性只能被初始化为一个字符值或一个常量,不能使用表达式。 所以你可以把静态属性初始化为整型或数组,但不能指向另一个变量或函数返回值,也不能指向一个对象。

class Foo {
    public static $my_static = 'foo';

    public function staticValue() {
        return self::$my_static;
    }
}

$foo = new Foo();
echo $foo->staticValue();

class Bar extends Foo {
    public function fooStatic() {
        return parent::$my_static;
    }
}

$bar = new Bar();
echo $bar->fooStatic();
echo '<br/>';
echo Bar::$my_static;

抽象类

abstract class AbstractClass
{
    // 强制要求子类定义这些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue() . '<br/>';
    }
}

class ConcreteClass1 extends AbstractClass {
    public function getValue()
    {
        // TODO: Implement getValue() method.
        echo 'ConcreteClass1<br/>';
    }

    public function prefixValue($prefix)
    {
        // TODO: Implement prefixValue() method.
        echo "{$prefix}ConcreteClass1<br/>";
    }
}

class ConcreteClass2 extends AbstractClass {
    public function getValue()
    {
        // TODO: Implement getValue() method.
        echo 'ConcreteClass2<br/>';
    }

    public function prefixValue($prefix)
    {
        // TODO: Implement prefixValue() method.
        echo "{$prefix}ConcreteClass2<br/>";
    }
}

$concrete1 = new ConcreteClass1();
$concrete1->printOut();
$concrete1->prefixValue('FOO__');

$concrete2 = new ConcreteClass2();
$concrete2->printOut();
$concrete2->prefixValue('FOO__');
// 第二个抽象类的例子
abstract class AbstractClass
{
    // 我们的抽象方法仅需要定义需要的参数
    abstract protected function prefixName($name);
}

class ConcreteClass extends AbstractClass {
    // 我们的子类可以定义父类签名中不存在的可选参数
    public function prefixName($name, $separator = '.')
    {
        // TODO: Implement prefixName() method.
        if ($name == 'Pacman') {
            $prefix = 'Mr';
        } elseif ($name == 'Pacwoman') {
            $prefix = 'Mrs';
        } else {
            $prefix = '';
        }

        return "{$prefix}{$separator}{$name}<br/>";
    }
}

$concrete = new ConcreteClass();
echo $concrete->prefixName('Pacman');
echo $concrete->prefixName('Pacwoman');

接口
指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
就像定义一个标准的类一样,但其中定义所有的方法都是空的。 接口中定义的所有方法都必须是public,这是接口的特性。

要实现一个接口,可以使用implements操作符。类中必须实现接口中定义的所有方法,否则会报一个fatal错误。
如果要实现多个接口,可以用逗号来分隔多个接口的名称。
实现多个接口时,接口中的方法不能有重名。
接口也可以继承,通过使用extends操作符。

PHP类是单继承,也就是不支持多继承,当一个类需要多个类的功能时,继承就无能为力了,为此PHP引入了接口技术

上一篇:[译]Java 垃圾回收介绍


下一篇:WPF学习之路(六)Command