PHP 中用 class
来定义类,用 new
来实例化对象,用 extends
继承类,不过只能单继承。属性和方法有 public
、private
和 protected
做访问控制,默认为 public
,在类里定义常量不需要 $
,用(::
)范围解析符可以调用父类的方法,访问类的静态变量、静态方法和常量。
基本概念
定义
- 每个类的定义都以关键字
class
开头,后面跟着类名(非保留字)。 - 类名后跟着一对花括号,里面包含有类属性和方法的定义。
<?php
class A
{
//属性
public $a;
private $b;
//方法
public function actionA()
{
}
}
类成员默认值
在定义类属性的时候,可以使用默认值
<?php
class A
{
//默认值
public $a = 'Hi';
private $b = 'Hello';
//方法
public function actionA()
{
}
}
创建实例
要创建一个对象的实例,使用关键字 new
<?php
$a = new A();//创建类 A 的实例
对象赋值
当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用克隆给一个已创建的对象建立一个新实例。
<?php
class A
{
}
$a = new A();
$b = $a;
$c = &$a;
$d = clone $a;
$a = null;
var_dump($a,$b,$c,$d);
$this
伪变量 $this 可以在当一个方法在对象内部调用时使用。$this 是一个到调用对象(通常是方法所属于的对象,但也可以是另一个对象,如果该方法是从第二个对象内静态调用的话)的引用。
<?php
class A
{
function actionA()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo '$this is not defined.'.PHP_EOL;
}
}
}
class B
{
function actionB()
{
A::actionA();
}
}
$a = new A();
$a->actionA();
A::actionA();
$b = new B();
$b->actionB();
B::actionB();
从结果可以看出,$this 只能在对象中使用,不能在静态方法中调用。但是如果在另一个对象(类 B)中调用静态方法,则 $this
指向该类( B )。
对象继承
一个类可以在声明中用 extends
关键字继承另一个类的方法和成员。PHP 不支持多重继承,一个类只能继承一个类。
class A
{
}
class B extends A
{
}
被继承的方法和成员可以通过用同样的名字重新声明被覆盖,除非父类定义方法时使用了 final
关键字。可以通过 parent::
来访问被覆盖的方法或成员。
<?php
class A
{
public function sayHi()
{
echo "Hi".PHP_EOL;
}
final public function sayBye()
{
echo "Bye".PHP_EOL;
}
}
class B extends A
{
public function sayHi()
{
parent::sayHi();
echo "Hello".PHP_EOL;
parent::sayBye();
}
//不能被覆盖,报错,练习的时候注意删除该方法
public function sayBye()
{
echo "See you";
}
}
$b = new B();
$b->sayHi();
从结果可以看到
- 使用
final
修饰的方法不能被覆盖 - 使用
parent::
可以调用父类方法或属性
属性
定义
类的变量成员叫做属性。属性声明是由访问控制关键字 public
,protected
或 private
和一个变量来组成,同时可以加上默认值。
<?php
class A
{
//只能在类本身使用
private $a = "Hello";
//可以在子类和类本身使用
protected $b = <<<EOT
This is variable b;
EOT;
//除了子类,类本身,外部也可以访问
public $c;
}
访问属性
在类的成员方法里面,可以通过 $this->
加变量名来访问类的属性和方法,但是要访问类的静态属性或者在静态方法要使用 self::
加变量名。
注意 self::
这种方式后的变量名需要加 $ 符号,而 $this-> 后的变量名不需要加
<?php
class A
{
private $a = "Hello";
protected $b = <<<EOT
This is property b
EOT;
public static $c = 'This is a'.' static property';
public function talk()
{
echo $this->a.PHP_EOL;
echo $this->b.PHP_EOL;
echo self::$c;
}
}
(new A())->talk();
类常量
我们可以在类中定义常量。常量的值将始终保持不变。在定义和使用常量的时候不需要使用 $
符号。
<?php
class A
{
const ENV = 'env';
const HELLO = 'Hello';
}
接口(interface)中也可以定义常量
<?php
interface B
{
const ENV = 'ENV';
public function sayHi();
}
自动加载对象
要进行一个类操作时,需要先将该类加载进来,例如 include
,require
等。
如果要执行的类很多,则需要大量 include
操作,会导致重复加载,管理苦难等一系列问题。
在 PHP 5 中,不用这样做了,可以使用 spl_autoload_register()
函数来注册任意数量的自动加载器。
<?php
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});
new A();
new B();
本例尝试分别从 A.php 和 B.php 文件中加载 A 和 B 类,相当于
<?php
include 'A.php';
include 'B.php';
new A();
new B();
构造和析构函数
构造函数
void __constuct()
创建一个对象时( new
操作),构造函数会自动调用
class A
{
public function __construct()
{
echo 'init...'.PHP_EOL;
}
public function sayHi()
{
echo "hi";
}
}
(new A())->sayHi();
实例化 A 的时候执行构造函数。
注意: 如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用parent::__construct()。
<?php
class A
{
public function __construct()
{
echo "A";
}
}
class B extends A
{
public function __construct()
{
parent::__construct();
echo "B";
}
}
new A(); // A
new B(); // AB
析构函数
void __destruct( void )
析构函数会在当某个对象的所有引用都被删除或者当对象被显式销毁时执行。
<?php
class A {
public function __construct() {
echo 'Start...';
}
public function sayHi()
{
echo "Hi...";
}
public function __destruct() {
echo "Finish";
}
}
(new A())->sayHi(); // Start...Hi...Finish
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()
。
析构函数即使在使用 exit()
终止脚本运行时也会被调用。在析构函数中 调用 exit()
将会中止其余关闭操作的运行。
访问控制
对属性或方法的访问控制,是通过在前面添加关键字 public
、protected
或 private
来实现的。如果未添加,则默认为 public
。
-
public
所定义的类成员可以在任何地方被访问 -
protected
所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问) -
private
定义的类成员则只能被其所在类访问
<?php
class A
{
private $hi = 'Hi'.PHP_EOL;
protected $hello = 'Hello'.PHP_EOL;
public $bye = 'Bye'.PHP_EOL;
private function sayHi()
{
echo $this->hi;
}
protected function sayHello()
{
echo $this->hello;
}
public function sayBye()
{
echo $this->bye;
}
}
class B extends A
{
public function talk()
{
parent::sayHello();
}
}
$a = new A();
$a->sayBye();//报错,无法调用
$b = new B();
$b->sayHello();//报错,无法调用
$b->talk();
$b->sayBye();
从结果可知,声明为 private
的方法或属性无法在类外部调用,同时子类也无法调用该方法。
范围解析操作符(::)
范围解析操作符,可以简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。
当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。
<?php
class A
{
const CONST_A = 'A constant value';
public static function sayHello()
{
echo 'Hello';
}
}
class B extends A
{
public static $b = 'static var b';
/**
* 覆盖父类方法
*
*/
public static function sayHello()
{
echo parent::sayHello().' World'.PHP_EOL;
}
public static function actionB()
{
self::sayHello();
echo parent::CONST_A.PHP_EOL;
echo self::$b;
}
}
B::actionB();
从结果可知
- 使用
parent
,self
可以调用父类和自身的方法属性 -
::
可以调用静态方法,静态属性和常量
网友评论