面向对象

1、魔术方法

方法名 描述
__construct() 类的构造函数
__destruct() 类的析构函数
__call($funName, $arguments) 当调用一个未定义或不可达方法时, __call() 方法将被调用。
__callStatic($funName, $arguments) 当调用一个未定义或不可达的静态方法时, __callStatic() 方法将被调用。
__get($propertyName) 当获取一个类的成员变量时, __get() 方法将被调用。
__set($property, $value) 当赋值一个类的成员变量时, __set() 方法将被调用。
__isset($content) 当调用 isset() 或 empty() 对一个未定义或不可达的成员赋值时, __isset() 方法将被调用。
__unset($content) 当调用 reset() 对一个未定义或不可达的成员更新时, __unset() 方法将被调用。
__sleep() 当执行序列化 serialize() 时,__sleep() 方法将首先被调用。
__wakeup() 当执行反序列化 deserialization() 时, __wakeup() 方法将首先被调用。
__toString() 当使用 echo 方法直接输出显示对象时,__toString() 方法首先被调用。
__invoke() 使用调用函数(function)访问一个对象时, __invoke() 方法将首先被调用。
__set_state($an_array) 当调用 var_export() 方法时,__set_state() 方法将被调用。
__clone() 当对象被复制赋值时,__clone() 方法将被调用。
__autoload($className) 试图载入一个未定义的类时调用。
__debugInfo() 输出 debug 信息。

__call(funame,funvalue)

执行条件 : 为了避免当调用的方法不存在时产生错误,可以使用 call() 方法来避免。该方法在调用的 方法不存在时会自动调用,程序仍会继续执行下去。 格式:call(参数1,参数2) 注意:__call()函数里面必须写两个参数


class Animal
{
    // 创建一个类外不可访问的方法    
    protected function eat($name)
    {
        echo "偷吃食物".'<br>';
    }
    // 在对象中调用一个不可访问方法时,__call() 会被调用
    public function __call($name, $value)
    {
        var_dump($name);// 结果是被调用的方法的名称
        var_dump($value);// 结果是传递过来参数的个数 , 其类型是数组
    }
}
$xb = new Animal();
$xb->eat();// 调用类外不可直接访问的方法

get(funame) set(funame,funvalue)

执行条件 : 读取不可访问属性的值时,get() 与set会被调用。 格式:set(参数1,参数2), get(参数) 注意:set()函数里面必须写两个参数 ,get函数里面必须写一个参数


class Animal
{
    // 设置两个类外面不能访问的属性
    protected $age;
    private $money;
    // 1.读取不可访问属性的值时,__get() 会被调用
    public function __get($name)
    {
        var_dump($name);// 结果得到的是对应的属性的名称
    }
    // 2.在给不可访问属性赋值时,__set() 会被调用。
    public function __set($name, $value)
    {
        var_dump($name);// 结果得到的是对应的属性名称
        var_dump($value);// 结果得到的是对应的修改的值
    }
}
$xb = new Animal(0, 0);
// 1.调用类中不可访问的属性
$xb->age;
$xb->money;
// 2.给类中的属性赋值
$xb->age = 1;
$xb->money = 10000;

__isset(funame)

执行条件 : 当对不可访问属性调用 isset() 或 empty() 时, isset() 会被调用。 格式:isset([参数]) 注意:__isset()函数里面必须写一个参数

class Animal
{
    // 创建一个类外不可访问的方法
    protected function eat()
    {
        echo "偷吃食物".'<br>';
    }
    // 当对不可访问属性调用 isset() 或 empty() 时, __isset() 会被调用。
    public function __isset($name)
    {
        var_dump($name);// 结果是被调用的方法的名称
    }
}
$xb = new Animal();
isset($xb->age);

__unset(funame)

执行条件 : 当对不可访问属性调用 unset() 时,unset() 会被调用。 格式:unset([参数]) 注意:__unset()函数里面必须写一个参数

class Animal
{
    // 创建不可访问的属性
    protected $age = 1;
    // 当对不可访问属性调用 unset() 时,__unset() 会被调用。
    public function __unset($name)
    {
        // var_dump($name);// 结果是被调用的方法的名称
        unset($this->$name);
        echo $this->age;// 无法再访问到 age 属性
    }
}
$xb = new Animal();
unset($xb->age);// 销毁属性 age

__toString

执行条件 : 该方法用于一个类被当成字符串时应怎样回应。

class Animal
{
    // 方法用于一个类被当成字符串时应怎样回应。
    public function __toString()
    {
        return "对象又被当成字符串了".'<br>';// 注意这里一定要返回一个字符串值
    }
}
$xb = new Animal();
echo $xb;// echo输出的是字符串

2、静态,关键字是static

静态成员 : 指的是在类中声明成员时可以加上static关键字 , 这样声明的成员就叫做静态成员。即声明为 static的类成员便能在类的范围内同享。 也就是这个静态成员对于这个类来说是唯一的,也就是不管有多少个对象,只要它引用了一个静态成 员,那么这些对象引用出来的肯定是同一个。

定义一个名为 'Animal' 的类 , 在其中存在一个静态属性 '$age' , 静态方法 'test':


class Animal
{
    // 1.定义静态属性
    public static $age = 16;// 静态属性
    // 2.定义静态方法
    public static function test()
    {
        echo "我是静态的方法 test".'<br>';
    }
}

在类外面静态成员的访问


Animal::$age;// 调用静态属性
Animal::test();// 调用静态方法

在类里面静态成员的访问


self::$age;// 调用静态属性
self::test();// 调用静态方法

3.静态与非静态的调用

在普通方法中调用静态成员:


class Animal
{
    public $color = '普通属性 color'.'<br>';// 普通属性
    public static $age = '静态属性 age'.'<br>';// 静态属性
    // 定义普通方法
    public function common()
    {
        echo "我是普通方法 common".'<br>';
        echo self::$age;
        self::test();
    }
    // 定义静态方法
    public static function test()
    {
        echo "我是静态的方法 test".'<br>';
    }
}
$xb = new Animal();
$xb->common();
/*
结果:
我是普通方法 common
静态属性 age
我是静态的方法 test
*/

在静态方法中调用普通成员:

class Animal
{
    public $color = '普通属性 color'.'<br>';// 普通属性
    public static $age = '静态属性 age'.'<br>';// 静态属性
    // 定义普通方法
    public function common()
    {
        echo "我是普通方法 common".'<br>';
    }
    // 定义静态方法
    public static function test()
    {
        echo "我是静态的方法 test".'<br>';
        echo $this->color;
        $this->common;
    }
}
Animal::test();
// 结果报错

静态成员的特点总结:


静态数据成员和普通数据成员区别较大,体现在下面几点:

1. 普通数据成员属于类的一个具体的对象,只有对象被创建了,普通数据成员才会被分配内存。而静
   态数据成员属于整个类,即使没有任何对象创建,类的静态数据成员变量也存在。
2. 因为类的静态数据成员的存在不依赖与于任何类对象的存在,类的静态数据成员应该在代码中被显
   式地初始化,一般要在类内进行。
3. 外部访问类的静态成员能直接通过类名来访问。
4. 类实例化对象可以访问静态方法,但不能访问静态属性
5. 类的静态成员函数无法直接访问普通数据成员(可以通过对象名间接的访问),而类的任何成员函
   数都可以访问类的静态数据成员。
6. 静态成员和类的普通成员一样,也具有public、protected、private3种访问级别。

类常量

以前定义常量使用 'define' 函数定义 , 这种常量是全局常量 , 在任何地方都可以被访问到 , 而类常量则是
专属于该类的常量。
例:
定义一个类常量 'NAME' 并且分别在类外和类中调用:
class Person
{
    const NAME = 'jack';// 定义一个类常量
    public static function get()
    {
        // 静态方法调用类常量
        echo self::NAME;
    }
}
// 类外调用类常量
echo Person::NAME;
Person::get();
// 结果 jackjack

2.类常量与全局常量的区别


define('NAME', 'alice');// 定义一个全局常量 NAME
class Person
{
    // 定义一个类常量 NAME
    const NAME = 'jack';
}
class Animal
{
    // 定义一个类常量 NAME
    const NAME = '小白';
    public static function get()
    {
        echo 'Animal 类的 NAME '.self::NAME.'<br>';// 调用类常量 NAME
        echo 'Person 类的 NAME '.Person::NAME.'<br>';// 调用类常量 NAME
        echo '全局的 NAME '.NAME.'<br>';// 调用全局常量 NAME
        echo "<br>";
    }
}
echo Animal::get();
echo NAME.'<br>';// 调用全局的常量 NAME
echo Person::NAME.'<br>';// 调用 Person 类的 NAME
echo Animal::NAME.'<br>';// 调用 Animal 类的 NAME

总结 : 全局常量可以不用使用任何标识符直接在任何地方调用到 , 而类常量必须使用对应的类名称或代

表类名称的关键字来使用。

继承

例:

创建两个类 , 让其中的 Xh 继承 Ha 类 , 继承之后子类 Xh 中自动可以拥有父类 Ha 中的成员:


// 父类 Ha
class Ha
{
    // 父类的两个 公有 属性
    public $color = '黑白'.'<br>';
    public $ear = '竖着'.'<br>';
    // 父类的一个 公有 方法
    public function skill()
    {
        echo "拆家".'<br>';
    }
}
// 创建父类对象
$dh = new Ha();
// 父类调用父类成员
echo $dh->color;
echo $dh->skill();
// 子类 Xh
class Xh extends Ha
{
}
// 创建子类对象 子类中没有创建任何成员
$xh = new Xh();
// 子类调用成员
echo $xh->ear;
echo $xh->skill();
/*
结果:
黑白
拆家
竖着
拆家
*/

继承的优点 : 在软件开发中,类的继承性使所建立的软件 具有开放性、可扩充性,这是信息组织与分类的行之有效的 方法,它简化了对象、类的创建工作量,增加了代码的可重性。

2.多重继承

多重继承就类似于 " 小明爷爷的东西会传给小明的父亲 , 小明父亲的东西又会传给小明 , 这些东西中就 存在小明爷爷传给小明父亲的东西"。


// 爷爷类
class GrandFather
{
    public $name = '爷爷类'.'<br>';
}
// 父亲类
class Father extends GrandFather
{
    public $age = 0 .'<br>';
}
// 小明类
class XiaoMing extends Father
{
    public $sex = 'man'.'<br>';
}
// 创建小明类的对象
$xh = new XiaoMing();
// 通过小明类来调用父亲类,爷爷类和小明类的成员
echo $xh->name;
echo $xh->age;
echo $xh->sex;
/*
结果:
爷爷类
0
man
*/

小明类可以调用到父亲类和爷爷类的非私有成员 , 小明类除了继承了父亲类的非私有成员外还继承了爷 爷类的非私有成员 , 这样的继承自多个类的就称之为 多重继承。

重写

重写:就是当子类继承父类的一些方法后,子类又在其内部定义了相同的方法,则这个新定义的方法会 覆盖继承而来的父类的方法,子类只能调用其内部定义的方法。 重写的要求 : 1.当一个父类和子类有一个方法,参数和方法名字完全一致,那么子类方法会覆盖父类的方法。 2.必须参数一致,才会实现方法覆盖。当参数个数不一致,则会报错。当方法名字不一致,就不会 覆盖,只是子类新定义的方法。 3.要求参数相同,具体就是要求参数的个数与父类相同,而并不是参数名称一致。即传递的参数名 字可以为任意,只要保证传递的个数相同即可。 4.在实行方法覆盖的时候,访问修饰符可以是不一样的,但是子类的访问范围必须大于等于父类的 访问范围。

例: 创建一个父类 Animal 类 , 创建一个子类 Dog 类继承自 Animal 类 , 在 Dog 类中创建与父类 Animal 类中同名的 move 方法 , 创建子类的对象调用其中同名的方 法:


// 创建一个 Animal 类
class Animal
{
    // Animal 类中创建 move 方法
    public function move()
    {
        echo "动物能动".'<br>';
    }
}
class Dog extends Animal
{
    // 创建一个和父类同名的方法 注意方法名和参数个数相同,另外子类的访问权限修饰符要大于父类的访问
    权限修饰符
        public function move()
    {
        echo "狗能跑,能游泳".'<br>';
    }
}
// 创建子类对象
$xh = new Dog();
// 通过子类调用类中同名的方法

$xh->move();
/*
结果: 狗能跑,能游泳 (调用到的是子类的方法)
*/
最后结果调用的是子类的 move 方法。
思考 : 子类重写父类的方法后能否在获取到父类中同名的方法呢? 该如何调用?
parent : parent关键字表示父类 , 可以通过 parent 关键字调用被重写的父类的方法。

// 创建一个 Animal 类
class Animal
{
    // Animal 类中创建 move 方法
    public function move()
    {
        echo "动物能动".'<br>';
    }
}
class Dog extends Animal
{
    // 创建一个和父类同名的方法
    public function move()
    {
        echo "狗能跑,能游泳".'<br>';
    }
    // 调用当前类和父类方法的测试方法
    public function test()
    {
        parent::move();// 调用的是父类的 move 方法
        self::move();// 调用的是当前类的 move 方法
    }
}
$xh = new Dog();
$xh->test();
/*
结果 :
动物能动
狗能跑,能游泳
*/

封装

1.什么是封装 封装性(信息隐藏): 封装性是保证软件部件具有优良的模块性的基础。 面向对象的类是封装良好的模块,类定义将其说明(用户可见的外部接口)与实现(用户不可见的内部 实现)显式地分开,其内部实现按其具体定义的作用域提供保护。 2.封装的特点

对象是封装的最基本单位 , 封装防止了程序相互依赖性而带来的变动影响。面向对象的封装比传统语言 的封装更为清晰、更为有力。 例: 创建一个银行类 , 并实现 存钱 , 取钱 , 查询金额的操作:


/**
* 创建一个银行类
*/
class Bank
{
    public $money;// 这个金额不能在外部随意设置
    /**
* 初始化金额
*/
    public function __construct($money)
    {
        $this->money = $money;
    }
    /**
* 存钱操作
*/
    public function saveMoney($money)
    {
        $this->money += $money;
    }
    /**
* 取钱操作
*/
    public function getMoney($money)
    {
        $this->money -=  $money;
    }
    /**
* 查询金额操作
*/
    public function showMoney()
    {
        echo $this->money;
    }
}
$jack = new Bank(100);// 给 jack 开户,并存100元
$jack->showMoney();// 查看金额
$jack->saveMoney(100);// 存钱
$jack->showMoney();
$jack->getMoney(100);// 取钱
$jack->showMoney();
$jack->money = 10000;// 随意修改金额
$jack->showMoney();

/*
结果:
100
200
100
10000
*/

results matching ""

    No results matching ""