简介
下面用一个实例说明类和对象的简单使用方式
class MyClass
{
public $a = 1; // 对象属性
protected $b = 2; // 对象属性
private $c = 3; // 对象属性
// 构造函数
public function __construct() {
}
// 对象方法
public function getA() {
return $this->a;
}
}
$str = "MyClass"; // 当用到类名时,可使用类名字符串
$a = new MyClass; // 如果构造函数无参数,可省略括号
$b = new MyClass();
$c = new $str; // 使用类名字符串构造实例
$d = new $str();
类属性
使用类属性时,需要遵循以下规定:
1.类属性可以进行初始化,但必须使用编译阶段即可确定的常量。或一些常量表达式,例如:"1+2"、"'Hello'.'world'"等。
2.在类内部,非静态成员使用 "$this->成员名"的方式访问,静态成员使用 "self::成员名" 的方式进行访问。
3.字符串属性不能应用变量解析特性(使用heredoc或双引号方式时)。
4.类常量使用const进行声明,注意,常量名称前不能添加$符号,而且public/private/protected等访问修改符必须在const之前。
5.类静态成员使用static进行声明。
6.类的静态成员、常量属性、方法都可以不指定可访问修饰符,这时默认为public,类的非静态属性,则必须指定可访问修饰符。
class MyClass
{
public const PI = 3.14;
public static $name = "MyClass";
public $a = 1+2;
public $b = <<<"HERE"
hello world
HERE;
public function getInfo() {
echo MyClass::PI . "\n";
echo self::PI . "\n";
echo MyClass::$name . "\n";
echo self::$name . "\n";
echo $this->a . "\n";
echo $this->b . "\n";
}
}
$str = "MyClass"; // 当用到类名时,可使用类名字符串
$a = new MyClass;
$a->getInfo();
echo MyClass::PI . "\n";
echo MyClass::$name . "\n";
echo $a::PI . "\n";
echo $a::$name . "\n";
echo $str::PI . "\n";
echo $str::$name . "\n";
echo $a->a . "\n";
echo $a->b . "\n";
构造函数
类的构造函数使用固定的名称: __construct()
如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。
class MyClass
{
private $name = 1;
public function __construct(string $name = "none")
{
// 如果没有定义构造函数,类将自动继承次类的构造函数
// 如果类中定义了自己的构造函数,则父类构造函数不会自动调用
// 如果要调用父类构造函数,需自行调用
// parent::__construct();
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
$a = new MyClass();
$b = new MyClass("Ann");
echo $a->getName() . "\n"; // none
echo $b->getName() . "\n"; // Ann
对象可以动态添加和删除属性
class MyClass
{}
$a = new MyClass();
$a->a = "a";
$a->b = "b";
unset($a->a);
var_dump($a);
/*
object(MyClass)#1 (1) {
["b"]=>
string(1) "b"
}
*/
对象之间的赋值默认为引用赋值
当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。给一个已创建的对象建立一个新实例需要使用“克隆”的方式。
class MyClass { }
$a = new MyClass();
$b = new MyClass();
$c = $a; // a和c是不同的变量,但指向同一个内存实体
$d = &$b; // b和d是同一个变量,自然也是指向同一个内存实体
$a->x = "1";
$b->x = "2";
$c->x = "3";
$d->x = "4";
var_dump($a->x); // 3
var_dump($b->x); // 4
var_dump($c->x); // 3
var_dump($d->x); // 4
$b = $a; // a和b是不同变量,只是指向同一个内存实体
$c = &$a; // a和c是同一个变量
$a->x = "5";
$a = null;
var_dump($a); // NULL
var_dump($b); // ["x"]=>string(1) "5"
var_dump($c); // NULL
使用对象而非类创建对象
可以通过new一个对象来实例化一个对象,效果与直接使用类是一样的,可以将对象名当构造函数使用:
class Info
{
public $age = 10;
}
class MyClass
{
public $dat = 0;
public function __construct($dat)
{
$this->dat = $dat;
echo "new MyClass\n";
}
}
$i = new Info();
$a = new MyClass(2);
$a->x = "x";
$a->i = $i;
$b = new $a(3); // 如果没有参数,可省略括号
$b->y = "y";
$i->age = 20;
var_dump($a);
var_dump($b);
/*
new MyClass
new MyClass
object(MyClass)#2 (3) {
["dat"]=>
int(2)
["x"]=>
string(1) "x"
["i"]=>
object(Info)#1 (1) {
["age"]=>
int(20)
}
}
object(MyClass)#3 (2) {
["dat"]=>
int(3)
["y"]=>
string(1) "y"
}
*/
类内创建对象
在类的内部,可以有多种特殊方式可以创建对象,而且可以用于静态方法或对象方法
class MyClass
{
public static function getNew($x)
{
return new static($x); // 如果没有参数,可省略括号
}
public $dat = 0;
public function __construct($dat)
{
$this->dat = $dat;
}
}
$a = MyClass::getNew(3);
var_dump($a);
/*
object(MyClass)#1 (1) {
["dat"]=>
int(3)
}*/
class MyClass
{
public $dat = 0;
public function __construct($dat)
{
$this->dat = $dat;
}
public function getNew()
{
// 在类内部有以下方式可以创建当前类的对象
return new static($this->dat);
return new self($this->dat);
return new MyClass($this->dat);
}
}
$a = new MyClass(3);
$b = $a->getNew();
var_dump($b);
/*
object(MyClass)#2 (1) {
["dat"]=>
int(3)
}
*/
静态属性和方法
类的静态属性和方法使用static关键字进行声明,如果不添加可访问修饰符,则默认为public。注意,不能通过对象访问类的静态属性,但可以通过对象访问静态方法。
class MyClass
{
static public $id = 0; // 类变量
static public function put() { // 类方法
echo "MyClass put()\n";
}
}
$str = "MyClass";
$ca = new MyClass;
echo MyClass::$id . "\n";
echo $str::$id . "\n";
echo $ca::$id . "\n";
//echo $ca->id."\n"; // 非法
MyClass::put();
$str::put();
$ca::put();
$ca->put();
私有成员可以被同类对象访问
一个对象中的私有成员并非只在对象自身可以读写,同类对象只要有相应的方法,就可以读写同类的其他对象的私有成员
class MyClass
{
private $dat;
public function __construct($dat) {
$this->dat = $dat;
}
public function getDat() {
return $this->dat;
}
public function cloneDat(MyClass $x) {
$x->dat = $this->dat;
}
}
$a = new MyClass(2);
$b = new MyClass(3);
$a->cloneDat($b);
echo $b->getDat(); // 2
类定义的一般格式
[abstract/final] class classname [extends baseclass] [implements interfacename,[interfacename, ...]]
{
[use traitname, [traitname, ...];]
[[public/protected/private/static/const] $property[=value]; ...]
[[public/protected/private/static/final/abstract]function functionname(args) {}]
...
}
类定义示例
// 定义一个矩形类
class MyRectangle
{
private $width;
private $height;
public function __construct(float $width, float $height){
$this->width = $width;
$this->height = $height;
}
public function setLenght($width, $height) {
$ok = false;
if(is_numeric($width) && (float)$width>0) {
$ok = true;
$this->width = (float)$width;
}
if(is_numeric($height) && (float)$height>0) {
$ok = true;
$this->height = (float)$height;
}
if(!$ok)
throw new Exception("Error: [$width, $height]\n");
}
public function getArea(float $ratio=1) : float {
$area = $this->width * $this->height * $ratio;
if($area > 0)
return $area;
else
throw new Exception("Error: area == 0\n");
}
}
try {
$a = new MyRectangle(2, 3);
echo "面积为: " . $a->getArea() . "\n";
$a->setLenght(null, "4");
echo "面积为: " . $a->getArea(2) . "\n";
$a->setLenght(null, -3);
echo "面积为: " . $a->getArea(0) . "\n";
}
catch(Exception $e) {
echo $e->getMessage();
}