面向对象(OOP)-Object Oriented Programming
面向对象和面向过程
大象装冰箱
面向过程
- 打开冰箱门();
- 把大象装进去();
- 关闭冰箱门();
面向对象
- 建立对象, 冰箱, 大象
- 冰箱.开门();
- 大象.进冰箱();
- 冰箱.关门();
面向过程好写, 面向对象好改
类 对象
类实例化 ==> 对象
对象抽象 ==> 类
类有属性 ==> 面向过程 变量 age $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();