大概1年前我总结过,但是那时候太菜,现在我又来总结了。 (本文是总结,不是入门,刚学oop的不适合看,基础写的比较省略。)
0.思路
其实oop编程发展到现在,知识点很多,而且很杂,比如static就很乱,很容易混淆,我自己这么分类:
- 1.类和对象(创建类和对象的基本概念)
- 2.层级组织及其衍生(完善和增强类,创建层级,便于组织和复用代码)
- 3.其他工具和特性(各个语言都有的拦截器,序列化,php有的魔术方法等杂项)
1.类和对象
1.1类和对象的概念
类和对象是模拟现实中,一群相似的物体,以及他们的抽象模板的关系,在编程中便于将方法(功能)和属性(数据)组织到一起,做到封装,解耦,提高代码的健壮性和复用性。 是一个非常重要的概念发明。
类和对象的基本概念一言难尽,总结:
- 类的由属性和方法组成
- 属性和方法可以调用
- 类可以实例化(new)出对象
1.2可见性
属性和方法,都有三种可见性,分别用三个单词去修饰
在类的外部可访问 | 子类可访问 | |
---|---|---|
public | Y | Y |
protected | N | Y |
private | N | N |
1.3static作用域
类由属性和方法组成,属性和方法可以调用,一个类实例化成多个对象后,每个对象都有自己的属性和方法,而且调用同样的方法后结果不一定一样,这叫多态。
然而属性和方法不一定要实例化后才能调用,定义为static的属性和方法就是直接可以调用,无需实例化。
我这么理解,类是一个特殊的作用域,就当成一个特殊的对象,他持有静态属性和静态方法,对象也可以调用静态方法,但是类不能调用非静态方法。
对象改变静态属性的值后,当对象销毁了,静态属性的值还在,因为他属于类。
1.4自动加载
使用类前必须定义类,当前文件没有这个类,就要include,当应用变大,就会很难搞。 就要用到自动加载。
自动加载就是依靠spl_autoload_register()
实现,参数是一个函数,当找不到使用的类的时候,就会将类名作为参数传入注册的函数。
<?php
spl_autoload_register(function($class_name){
require_once 'www/app/lib/'.$calss_name.'.php';
})
复制代码
1.5构造函数
构造函数是最重要的一个魔术方法,所以提前单说。
2.层级设计及其衍生
发明类和对象的关系已经很厉害了,但是还不够,为了处理更加复杂的关系,出现了对象层级。
一个对象可以继承另一个对象,这样可以更好得组织代码和复用代码。然后还有抽象类,接口和trait都是oop中组织和复用代码的工具。
2.1继承和重载
- 一个对象可以继承另一个对象,这样他就具有了父对象的属性和方法
- 子对象可以覆盖父对象的方法
- 调用时优先在子对象寻找属性和方法,没有就去父类寻找
- 被final修饰的属性和方法无法重载
2.2抽象类 接口 trait
- 抽象类的代码是侧重规范性而非实现功能,跟伪代码有点像,他定义要实现哪些函数,但是不写具体实现。
- 接口跟抽象类很像,但是抽象类只能单继承,接口可以多继承。
- triat则是代码片段的复用。
一言难尽,直接说重点
是否多继承 | 代码是有功能性的还是规范性的 | |
---|---|---|
类 | N | 功能 |
抽象类 | N | 规范(主要)和功能 |
接口 | Y | 规范 |
trait | Y | 功能(主要)和规范 |
注意
- 1.抽象类
- 只要类中有抽象方法,就必须定义为抽象类,同时里面可以有非抽象方法
- 2.接口
- 接口的的方法都是public的,并且是没有内容的, 接口可以有常量
- 接口还可以继承接口,扩展
- 3.trait
- 可以有属性、方法、可以是静态的,
- 甚至可以写抽象方法,
- trait还可以包含trait,
- 导入trait的时候还能更改里面方法的可见性
2.3各种组合下的调用属性和方法
静态非静态*内外部+常量
class ClassA{
//属性
public $var1 = 1;
//静态属性 静态就是归类管,不归对象管
public static $var2 = 2;
//常量 常量不可更改 访问方式类似静态
const VAR3 = 3;
//非静态方法
public function m1(){
echo 'm1 working ......';
echo PHP_EOL;
//引入$this和self
//类内访问正常属性 不用加$
echo $this->var1;
echo PHP_EOL;
//类内访问静态属性 要加$ 用类名也行
echo self::$var2;
echo ClassA::$var2;
echo PHP_EOL;
//类内访问常量 就用类名 self也行
echo ClassA::VAR3;
echo self::VAR3;
echo PHP_EOL;
}
//静态方法
public static function m2(){
echo 'm2 working ......';
echo PHP_EOL;
//静态方法不能访问非静态属性或方法,因为没有实例,$this没意义
// echo $this->var1; //Fatal error: Uncaught Error: Using $this when not in object context
// echo PHP_EOL;
//类内访问静态属性 要加$ 用类名也行
echo self::$var2;
echo ClassA::$var2;
echo PHP_EOL;
//类内访问常量 就用类名 self也行
echo ClassA::VAR3;
echo self::VAR3;
echo PHP_EOL;
}
}
//调用非静态方法
(new ClassA())->m1();
//调用静态方法
ClassA::m2();
//测试在类外,调用属性
echo '----------';
echo PHP_EOL;
//非静态属性
echo (new ClassA())->var1;
echo PHP_EOL;
//静态属性
echo ClassA::$var2;
echo PHP_EOL;
//常量
echo ClassA::VAR3;
echo PHP_EOL;
复制代码
非静态 访问控制 重载和访问父级
/*非静态 访问控制 重载和访问父级*/
class ClassA{
//属性
public $var1 = 1;
protected $var2 = 2;
private $var3 = 3;
//方法
public function m1(){
echo 'm1 working ......';
echo $this->var1;
echo $this->var2;
echo $this->var3;
echo PHP_EOL;
}
protected function m2(){
echo 'm2 working ......';
echo $this->var1;//发现还是4 重载就就覆盖了 没有方法那样的保持层级
echo PHP_EOL;
}
private function m3(){
echo 'm3 working ......';
echo PHP_EOL;
}
}
$obj1 = new ClassA();
$obj1->m1();
//$obj1->m2();//Fatal error: Uncaught Error: Call to protected method ClassA::m2()
//$obj1->m3();//Fatal error: Uncaught Error: Call to private method ClassA::m3()
echo '--------------------';
echo PHP_EOL;
class ClassB extends ClassA{
//属性 这里叫重载
public $var1 = 4;
private $var3 = 6;
//方法 重载m1
public function m1(){
echo 'm1 working ......';
echo $this->var1;
//echo parent::var1;//这是错误的 只有静态才能这样调用
echo $this->var2;//没有重载就调用父类的属性
echo $this->var3;
echo PHP_EOL;
}
//重载m2
public function m2(){
echo 'class B m2 working ......';
// echo parent::$var1; 属性没有这种调用,如果没有
echo PHP_EOL;
parent::m2();
}
public function m4(){
echo 'm4 working ......';
// $this->m3();//Fatal error: Uncaught Error: Call to private method ClassA::m3()
}
}
$obj2 = new ClassB();
$obj2->m1();
$obj2->m2();
$obj2->m4();
复制代码
静态 访问控制 重载和访问父级
/*静态 访问控制 重载和访问父级*/
class ClassA{
//属性
public static $var1 = 1;
protected static $var2 = 2;
private static $var3 = 3;
//方法
public static function m1(){
echo 'm1 working ......';
echo self::$var1;
echo self::$var2;
echo self::$var3;
echo PHP_EOL;
self::m2();
}
protected static function m2(){
echo 'm2@A working ......';
echo PHP_EOL;
}
private static function m3(){
echo 'm3 working ......';
echo PHP_EOL;
}
}
echo ClassA::$var1;
echo PHP_EOL;
// echo ClassA::$var2;//Fatal error: Uncaught Error: Cannot access protected property ClassA::$var2
ClassA::m1();
// ClassA::m2();//Fatal error: Uncaught Error: Call to protected method ClassA::m2()
//$obj1->m2();//Fatal error: Uncaught Error: Call to protected method ClassA::m2()
echo '--------------------';
echo PHP_EOL;
class ClassB extends ClassA{
//属性 重载
public static $var1 = 4;
//方法 重载m1
public static function m1(){
echo 'm1@B working ......';
echo self::$var1;
echo parent::$var1;
echo self::$var2;
// echo self::$var3;//Fatal error: Uncaught Error: Cannot access property ClassB::$var3
echo PHP_EOL;
self::m2();
parent::m2();
}
protected static function m2(){
echo 'm2@B working ......';
echo PHP_EOL;
}
}
ClassB::m1();
复制代码
3.其他
- 魔术方法
- 常用8
- __construct() __destruct(),
- __call() __callStatic(),
- __get() __set() __isset() __unset(),
- 不常用4
- __sleep() __wakeup(),
- __toString(),
- __invoke(),
- 我不会3
- __set_state(),
- __clone()
- __debugInfo()
- 常用8
- 相关函数
- get_class()
- instanceof ()
- ::class
- 对象操作
- 对象序列化
- 对象比较
- 对象遍历
- 对象复制
- 其他
- 类型约束
- 应用的理解
- 匿名类
- static延迟绑定
魔术方法
1 | __construct() __destruct() | 构建和析构方法,在创建和销毁对象时调用 |
2 | __call() __callStatic() | 调用不存在的方法时调用 |
3 | __set(),__get(),__isset(),__unset() | 拦截器系列 |
4 | __sleep() __wakeup() | 在serialize()unserialize()时调用,可以额外加一些逻辑 |
5 | __toString() | 在echo时调用,不定义就echo会error |
6 | __invoke() | 当以函数方式调用对象时启动 |
7 | __set_state() __debugInfo() | 我也不知道有啥用 |
8 | __clone() | 自定义如何复制对象 |
/*魔术方法2*/
/*sleep wakeup invoke toString*/
class B{
function __construct($name,$age){
$this->name = $name;
$this->age = $age;
}
function __sleep(){
echo $this->name.'is sleep';
echo PHP_EOL;
return array('name','age');
}
function __wakeup(){
echo $this->name.'is wakeup';
echo PHP_EOL;
}
function __toString(){
return 'i am '.$this->name;
}
function invoke($arg){
echo 'what are u doing';
echo PHP_EOL;
}
}
//sleep
$obj = new B('hahaha','19');
$data = serialize($obj);
var_dump($data);
$test = unserialize($data);
//tostring
echo $test;
//invoke
$test('111');
/*魔术方法1*/
/*构建 析构 call get*/
class A{
public $name = 'default';
public $data = [];
//构建方法
public function __construct($name=NULL){
if($name){
$this->name = $name;
}
echo '__construct runing.....';
echo PHP_EOL;
}
//析构方法
public function __destruct(){
echo '__destruct runing.....';
echo PHP_EOL;
}
//拦截器
public function __call($name,$arguments){
echo 'you are try to run method'.$name.'but its not exists';
echo PHP_EOL;
}
public static function __callStatic($name,$arguments){
echo 'you are try to run static method'.$name.'but its not exists';
echo PHP_EOL;
}
//获取器设置器
public function __set($name,$value){
$this->data[$name] = $value;
echo 'setter runing ';
echo PHP_EOL;
}
public function __get($name){
if(isset($this->data[$name])){
return $this->data[$name];
}else{
return 'empty';
}
}
public function __isset($name){
if(isset($this->data[$name])){
echo 'Y';
}else{
echo 'N';
}
echo PHP_EOL;
}
public function __unset($name){
if(isset($this->data[$name])){
unset($this->data[$name]);
}
echo 'done ';
echo PHP_EOL;
}
}
$obj = new A('xyz');
echo $obj->name;
echo PHP_EOL;
$obj->tag = 'mmmm';
echo $obj->tag;
echo PHP_EOL;
echo $obj->bag;
echo PHP_EOL;
echo $obj->run();
echo PHP_EOL;
echo A::fly();
echo PHP_EOL;
复制代码
static有两种意思
- 1.区分作用域在类还是对象,静态变量是类作用域
- 2.有“最初调用类”的意思,主要2个用法,
- new static,
- 和延迟静态绑定static::funct()