[PHP从小白到大牛]-033 PHP-面向对象(一)

940 阅读4分钟

面向对象(OOP)-Object Oriented Programming

面向对象和面向过程

大象装冰箱

面向过程

  1. 打开冰箱门();
  2. 把大象装进去();
  3. 关闭冰箱门();

面向对象

  1. 建立对象, 冰箱, 大象
    1. 冰箱.开门();
    2. 大象.进冰箱();
    3. 冰箱.关门();

面向过程好写, 面向对象好改

类 对象

类实例化 ==> 对象

对象抽象 ==> 类

类有属性 ==> 面向过程 变量 nameage $sex

类有方法 ==> 面向过程 函数 eat() drink() whore() bet()

封装

把内部逻辑封装起来, 外部只有调用的权限, 没有修改的权限

继承

子类可以继承父类的属性和方法

金刚鹦鹉(学舌(),毛,飞(),生长()) 鹦鹉类(学舌(),毛,飞(),生长()) ===> 鸟类(毛,飞(),生长()) ====> 生物(生长())

多态

调用者不一样, 执行逻辑不同

如何声明一个类

语法

[修饰符] class 类名{
	[属性]
	[方法]
}

类名的命名规范(大驼峰)

<?php

class Person
{
    public $name = 'xujunhao';
    public $sex = "male";
    public $age = "18";
}

属性中的变量可以初始化, 但是初始化的值, 必须是常数, 可以直接获取值, 不需要运算

从类实例化对象

$对象名 = new 类名() // ()可加可不加

调用类的属性和方法, 用->

<?php

class Person
{

    public $name = null;
    public $sex = null;
    public $age = null;

    public function eat()
    {
        echo "吃肉!";
    }

    public function drink()
    {
        echo "我要喝酒!";
    }

}

$student = new Person();

$student->drink();
$student->name = "zhangsan"; // 属性赋值

echo $student->name; // 属性调用

$this 当前方法或属性的调用者

复习: 按值传递, 按引用传递

按引用传递

$a = 123;
$b = &$a;
$a = 456;
echo $b; // 456

按值传递

$a = 123;
$b = $a;
$a = 456;
echo $b; // 123

对象之间的赋值, 是按引用传递

<?php

class Person{
    public $name = null;
}

$student = new Person();
$teacher = $student;
$student->name = "zhangsan";
echo $teacher->name;

继承

class A extends B{

}
// A是子类, B是父类

封装

权限控制符, 用来修饰属性或者方法

权限控制符 public(公共的) protected(受保护的) private(私人的)

调用位置 public protected private
类外部(实例化对象) × ×
类内部(子类) ×
类内部(自身)
  • public 都可以访问到
<?php
// 类外部, 对象
class Person{
    public $name = "zhansan";

}
$student = new Person();
echo $student->name;
<?php
// 类内部, 自身
class Person{
    public $name = "zhansan";
    public function getName(){
        echo $this->name;
    }
}
$student = new Person();
echo $student->getName();
<?php
// 类内部, 子类
class Person{
    public $name = "zhansan";
    public function getName(){
        echo $this->name;
    }
}

class Student extends Person{
    public function test(){
        echo $this->name;
    }
}

$student = new Student();
echo $student->test();
  • protected 子类和自身可以调用, 外部不能调用
<?php

class Person{
    protected $name = "zhansan";
    public function getName(){
        echo $this->name;
    }
}

class Student extends Person{
    public function test(){
        echo $this->getName(); // 子类
    }
}

$student = new Student();
echo $student->test();
<?php

class Person{
    protected $name = "zhansan";
    public function getName(){
        echo $this->name;
    }
}

class Student extends Person{

}

$student = new Student();
echo $student->name; // 外部不能直接调用
<?php
// 自身可以调用
class Person{
    protected $name = "zhansan";
    public function getName(){
        echo $this->name;
    }
}

$student = new Person();
echo $student->getName();
  • privated 私人, 最严格的权限, 只有自身可以调用
<?php

class Person{
    private $name = "zhansan";
    public function getName(){
        echo $this->name; // 自身可以调用
    }
}

$student = new Person();
echo $student->getName();
<?php

class Person{
    private $name = "zhansan";
    public function getName(){
        echo $this->name;
    }
}

class Student extends Person{
    public function test(){
        echo $this->name; // 子类中不能调用父类的private属性
    }
}

$student = new Student();
echo $student->test();
<?php

class Person{
    private $name = "zhansan";
    public function getName(){
        echo $this->name;
    }
}

class Student extends Person{
    public function test(){
        echo $this->getName();
    }
}

$student = new Person();
echo $student->name; // 类外部, 不能直接调用private属性

魔术方法

构造方法__construct()

实例化对象的时候, 自动触发

析构方法__destruct

对象销毁的时候, 自动触发

<?php

class Person{
    public $name = "zhansan";

    public function __construct()
    {
        echo "对象已经实例化了!";
    }
    
    public function __destruct()
    {
        echo "对象被销毁了!";
    }

    public function getName(){
        echo $this->name;
    }
}

$student = new Person;
echo '------';
$student = null;
  • 触发析构方法的三种情况
    • 脚本结束
    • unset(对象)
    • 对象=null
<?php
// 使用构造方法, 给初始化对象时赋值
class Person{
    public $name = null;
    public $age = null;
    public $sex = null;

    public function __construct($a,$b,$c)
    {
        $this->name = $a;
        $this->age = $b;
        $this->sex = $c;
    }


}

$student1 = new Person('张三',18,'male');
$student2 = new Person('李四',19,'female');
$student3 = new Person('王五',20,'unknown');


echo $student1->name;
echo $student2->name;
echo $student3->name;

静态属性, 静态方法

static 来定义静态属性和静态方法, 不用实例化对象, 就可以直接访问, 只能用类来访问, 使用::来调用

<?php

class Test{
    public static $course = "English";
    public static $score;
}
echo Test::$course;
<?php

class Test{
    public static $course = "English";
    public static $score = 0;

    public static function hello(){
        echo self::$score = 100; // 内部调用, 使用self::属性/方法名
    }

}
echo Test::hello();

定义常量, 使用const关键字来定义一个常量, 一般常量名都是大写的, 区分大小写

常量不能修改值

<?php

class Test
{
    const age = 123;

}


Test::age = 456; // 报错

常量只能使用静态方式来调用::

<?php

class Test
{
    const age = 123;

}

$obj = Test();
echo $obj->age; // 报错
echo Test::age; // 123

重载

通过魔术方法, 动态的创建类属性和类方法

属性重载

当调用当前环境下未定义或者不可见的类属性或类方法时, 重载方法会被调用

  • 不可访问的属性赋值, 触发__set()
<?php

class Person
{
    private $sex = 'male';

    public function __set($name, $value)
    {
        echo $name, '  ', $value;
    }

}

$stu = new Person();
$stu->sex = 'female';
  • 获取不可访问的属性值, 触发__get()
<?php

class Person
{
    private $sex = 'male';
    protected $age = 39;

    public function __get($name)
    {
        if ($name == 'age') {
            echo "年龄 不是你想看, 想看就能看";
        }
    }


}

$stu = new Person();
$stu->age;
  • 当对不可访问属性调用isset()empty()时,__isset()会被调用
<?php

class Person
{
    private $sex = 'male';
    protected $age = 39;


    public function __isset($name)
    {
        echo $name;
    }

}

$stu = new Person();
isset($stu->sex);
  • 当对不可访问属性调用unset()时,__unset()会被调用。
<?php

class Person
{
    private $sex = 'male';
    protected $age = 39;


    public function __unset($name)
    {
        echo "您正在尝试销毁一个没有权限的属性 $name";
        unset(this->$name);
    }
}

$stu = new Person();
unset($stu->sex);

方法重载

  • 在对象中调用一个不可访问方法时,__call()会被调用。
<?php

class Person
{
    private $sex = 'male';
    protected $age = 39;


    public function __call($name, $arguments)
    {
        var_dump($name); // 方法名字
        var_dump($arguments); // 参数数组
    }

    protected function getSex()
    {
        echo $this->sex;
    }
}

$stu = new Person();
$stu->getSex(1, 2, 3, 4);
  • 在静态上下文中调用一个不可访问方法时,__callStatic()会被调用
<?php

class Animal
{
    private function eat()
    {
        echo 'eat';
    }


    public static function __callStatic($name, $arguments)
    {
        echo '调用不存在的--静态--方法名是:' . $name . '参数是:';
        print_r($arguments);
    }
}

$animal = new Animal();

Animal::smile('可爱', '大笑', '微笑');

继承extends

子类继承父类所有公有的和受保护的属性和方法子类

<?php

class People
{
    public $name = "lisi";
    protected $age = 39;
    private $salary = 1000;
}

class Person extends People
{

}

$P1 = new Person();
echo $P1->name;
echo $P1->age; // 报错
echo $P1->salary; // 报错

继承关键字extends一个类继承另一个类,不能继承多个

<?php

class People
{
    public $name = "lisi";
    protected $age = 39;
    private $salary = 1000;
}

class Biology
{
    public $life = 100;
    public $sex = null;
}

class Person extends People,Biology
{
 	// php不支持多继承
}

重写

重写:继承父类中的方法,子类中定义的与父类同名的方法

当一个子类重写其父类中的方法时,PHP不会调用父类中已被重写的方法。是否调用父类的方法取决于子类

<?php


class Person
{
    public function sayHi()
    {
        echo "hi";
    }
}

class Student extends Person
{
    public function sayHi()
    {
        echo 'hello';
    }
}

$stu = new Student();
$stu->sayHi();

关键字parent::访问父类中的被重写的属性和方法

可以父类原有的代码上追加新的代码

<?php


class Person
{
    public function sayHi()
    {
        echo "hi";
    }
}

class Student extends Person
{
    public function sayHi()
    {
        parent::sayHi();
        echo " and say Hello";
    }
}

$stu = new Student();
$stu->sayHi();

final

如果一个类被声明为final,则不能被继承。

<?php

final class Person{
    public $name = 'lisi';
}

class Student extends Person{
    public $sex = 'male';
} // 报错, 不能继承
<?php

// 去掉final, 则没有问题
class Person
{
    public $name = 'lisi';
}

class Student extends Person
{
    public $sex = 'male';
}

如果父类中的方法被声明为final,则子类无法重写该方法。

<?php

// 继承父类的方法
class Person
{
    public $name = 'lisi';

    public function getName()
    {
        echo $this->name;
    }
}

class Student extends Person
{
    public function getName()
    {
        parent::getName();
        echo "\n";
        echo "可以继承父类!";
    }
}

$stu = new Student();
$stu->getName();

同样的代码, 如果在getName函数前, 添加final, 则会报错

<?php


class Person
{
    public $name = 'lisi';

    final public function getName() // 会报错
    {
        echo $this->name;
    }
}

class Student extends Person
{
    public function getName()
    {
        parent::getName();
        echo "\n";
        echo "可以继承父类!";
    }
}

$stu = new Student();
$stu->getName();