第8章 类与对象
1. 什么是类
1.1 类的声明与实例化
<?php
/**
* 类在使用前需要声明,声明一个类使用关键字class
* Class conn
*/
// 声明一个数据库连接类
class conn
{
private $dbtype = 'mysql'; // 数据库类型
private $host = '127.0.0.1'; // 数据库服务器IP
private $username = 'root'; // 用户名
private $password = '123456'; // 密码
private $pre = 'tb_'; // 数据库表前缀
// 插入数据
public function insert(){}
// 更新数据
public function update(){}
// 删除数据
public function delete(){}
// 查询数据
public function select(){}
}
// 实例化
$connObj = new conn();
var_dump($connObj);
?>
object(conn)#1 (5) {
["dbtype":"conn":private]=>
string(5) "mysql"
["host":"conn":private]=>
string(9) "127.0.0.1"
["username":"conn":private]=>
string(4) "root"
["password":"conn":private]=>
string(6) "123456"
["pre":"conn":private]=>
string(3) "tb_"
}
1.2 访问类中的成员
<?php
class conn2
{
public $dbtype = 'mysql';
private $pre = 'tb_';
public function test() {
echo 'test';
}
public function test2() {
echo $this->getPre();
}
public function getPre() {
echo $this->pre;
}
}
// 实例化conn2
$obj = new conn2();
// 可使用“->”访问类中的成员
$obj->test(); // test
echo "\n";
echo $obj->dbtype, "\n"; // mysql
/**
* 在对象方法执行的时候会自动定义一个$thiis的特殊变量,表示对象本身的引用。
* 通过$this->形式可以引用该对象的方法和属性,其作用是完成对象内部成员之间的访问。
*/
$obj->test2(); // tb_
?>
访问对象的成员有时还可以使用“::”符号。使用该符号一般有以下几种情况:
- parent:: 父类成员,这种形式的访问可调用父类的成员变量常量和方法。
- self:: 自身成员,这种形式的访问可调用当前类中的静态成员和变量
- 类名::成员,这种形式的访问可调用类中的变量常量和方法。
<?php
class conn3
{
public $dbtype = 'mysql';
// 在类中使用const定义常量HOST
const HOST = '127.0.0.1';
public function test() {
echo "test", "\n";
}
public function test1() {
echo self::HOST; // self访问常量HOST
self::getDbtype(); // self访问静态方法getDbtype()
}
// 使用static修饰的方法称为静态方法
public static function getDbtype() {
echo "mysql", "\n";
}
}
// 类对象实例化
$obj = new conn3();
$obj->test1(); // 127.0.0.1mysql
// 没有实例化类,使用“::”访问类中的方法
conn3::test(); // test
conn3::getDbtype(); // mysql
class conn4 extends conn3
{
public function testPrint() {
echo parent::test1();
}
}
$conn4 = new conn4();
$conn4->testPrint(); // 127.0.0.1mysql
?>
1.3 静态属性和静态方法
在PHP中,通过static关键词修饰的成员属性和方法称为静态属性和静态方法。静态属性和静态方法可在不被实例化的情况下直接使用。
-
静态属性
静态属性属于类本身,而不属于任何实例。静态属性使用static关键词定义,
- 在类外部使用“类名::静态属性名”的方式访问
- 在类内部可使用“self::静态属性名”的方式访问。
<?php
class myClass
{
static $staticVal = 0;
function getStatic() {
// self访问静态属性
echo self::$staticVal;
self::$staticVal++;
}
}
echo myClass::$staticVal; // 0
$obj = new myClass();
$obj->getStatic(); // 0
echo myClass::$staticVal; // 1
?>
- 静态方法
与静态属性相似,使用static修饰的方法称为静态方法,也可在不被实例化的情况下使用,其属于类而不是被限制到任何一个特定的对象实例。因此,$this在静态方法中不可使用,但可在对象实例中通过“$this->静态方法名”的形式调用静态方法,在类内部需要使用“self::静态方法名”的形式访问。
<?php
class myClass2
{
static $staticVal = 0;
public $val = 100;
static function getStaticVal() {
echo self::$staticVal;
}
static function changeStaticVal() {
self::$staticVal--;
echo self::$staticVal;
}
function change() {
// 在类内部使用$this调用静态方法
$this->changeStaticVal();
}
}
myClass2::getStaticVal(); // 0
myClass2::changeStaticVal(); // -1
$obj = new myClass2();
$obj->change(); // -2
?>
1.4 构造方法和析构方法
构造方法是在创建对象时自动调用的方法,析构方法是在对象销毁时自动调用的方法。
- 构造方法
构造方法常用的场景是在创建对象时用来给变量赋值,构造方法使用“__construct”定义。
<?php
class person
{
public $name;
public $age;
public $gender;
function __construct($name, $age, $gender)
{
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
}
function get($key) {
return $this->$key;
}
}
$test_1 = new person('张三', 18, '男');
echo $test_1->get('name'); // 张三
$test_2 = new person('李四', 16, '女');
echo $test_2->get('gender'); // 女
?>
- 析构方法
析构方法是在对象被销毁前自动执行的方法。使用“__destruct”定义。
在PHP中有一种垃圾回收机制,可自动清除不再使用的对象,释放内存。析构方法在垃圾回收程序执行之前被执行。
<?php
class person
{
public $name;
public $age;
public $gender;
function __construct($name, $age, $gender)
{
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
}
function get($key) {
return $this->$key;
}
function __destruct() {
echo "execute automatically before destroy", "\n";
}
}
$test_1 = new person('张三', 18, '男');
echo $test_1->get('name'), "\n"; // 张三
$test_2 = new person('李四', 16, '女');
echo $test_2->get('gender'), "\n"; // 女
?>
张三
女
execute automatically before destroy
execute automatically before destroy
2. 封装和继承
2.1 封装
可使用public、protected、private来修饰对象的属性和方法。使用不同修饰符的属性和方法,其可被访问的权限也不同:
- 使用public修饰的属性和方法可在任何地方调用
- 如果在类中的属性和方法前面没有修饰符,则默认修饰符为public
- 使用protected修饰的属性和方法可在本类和子类中被调用,在其他地方调用将会报错
- 使用private修饰的属性和方法只能在本类中被访问
<?php
class person2
{
public $name;
private $age;
protected $weight;
function __construct($name, $age, $weight)
{
$this->name = $name;
$this->age = $age;
$this->weight = $weight;
}
private function get($key) {
return $this->$key;
}
}
class personB extends person2{
function key($key) {
return $this->$key;
}
}
$obj = new person2('Tom', 22, '60kg');
echo $obj->name; // Tom
// echo $obj->age;
echo $obj->get('age');
$son = new personB('Beta', 18, '55kg');
echo $son->name; // Beta
echo $son->key('weight'); // 55kg
echo $son->key('age');
?>
<?php
class person2
{
public $name;
private $age;
protected $weight;
function __construct($name, $age, $weight)
{
$this->name = $name;
$this->age = $age;
$this->weight = $weight;
}
public function get($key)
{
return $this->$key;
}
}
class personB extends person2
{
function key($key)
{
return $this->$key;
}
}
$obj = new person2('Tom', 22, '60kg');
echo $obj->name; // Tom
// echo $obj->age;
echo $obj->get('age'); // 2
echo $obj->get('weight'); // 60kg
$son = new personB('Beta', 18, '55kg');
echo $son->name; // Beta
echo $son->key('weight'); // 55kg
// echo $son->key('age'); // 访问不到age
echo $son->get('age'); // 18
?>
2.2 继承特性
把一个类作为公共基类(父类),其他的类继承自这个基类,则其它类中都具有这个基类的属性和方法,其他类也可以各自额外定义自己不同的属性和方法。
- 类的继承使用关键词“extends”
- 在子类中可以使用parent访问父类的方法
- 在子类中可重写父类的方法
<?php
class student
{
public $name;
private $age;
protected $weight;
/**
* student constructor.
* @param $name
* @param $age
* @param $weight
*/
public function __construct($name, $age, $weight)
{
$this->name = $name;
$this->age = $age;
$this->weight = $weight;
}
function like() {
echo "I like study.";
}
function age() {
echo "I'm $this->name, $this->age years old this year.";
}
protected function get($key) {
return $this->$key;
}
function set($key, $value) {
$this->$key = $value;
}
}
class person extends student {
// 重写父类方法
function get($key)
{
echo $this->$key;
}
function what() {
parent::like(); // 子类中访问父类方法
}
function getAge() {
$this->age(); // 调用继承自父类的方法
}
}
// 使用继承自父类的__construct方法初始化实例
$obj = new person('张三', 18, '120kg');
$obj->get('name'); // 张三
$obj->get('weight'); // 120kg
$obj->what(); // I like study.
$obj->set('name', '李四');
$obj->getAge(); // I'm 李四, 18 years old this year.
?>
2.3 通过继承实现多态
多态通过继承复用代码而实现,可编写出健壮可扩展的代码,减少流程控制语句(if else)的使用。
<?php
class animal
{
function skill() {
echo "This function will be rewrite in the children.";
}
}
class fish extends animal{
function skill()
{
echo "I can swim!";
}
}
class dog extends animal{
function skill()
{
echo "I can run!";
}
}
function test($obj) {
$obj->skill();
}
test(new fish()); // I can swim!
test(new dog()); // I can run!
?>
往期文章: