面向对象是很重要的软件开发方法,可以说我们做开发的离不开它。
说到面向对象,那我们肯定会涉及到很多东西,比如类,函数,属性,方法等
因为是自己总结的,知识点比较零散,所以我会以概念+自身理解+代码示例来进行总结!
本质是变量 在类中就是类的属性 必须用var 或者 public private protected 等 用法: 对象->属性名
类的方法 也就是函数 用法:对象->方法名
class know {
var $ccc = 123;//本质是变量 在类中就是类的属性 必须用var 或者 public private protected 等 用法: 对象->属性名
public function b(){//类的方法 也就是函数 用法:对象->方法名
echo 111;
}
}
$a = new know();
print_r($a->b());//111
print_r($a->ccc);//123
和类中的变量不同 必须要赋值
放在一个类中 只能由这个类调用
const 常量名
调用 类名::常量名
class normal{
const zzs = 111;
}
$n = new normal();
echo $n::zzs;
在类中定义的 在实例化类的时候 会自动调用的方法
方法名字 __construct
通常用来 简化对象属性的初始化工作 还有一些要自动处理的 也可以写入里面
class construct{
var $aa ;
public function __construct($a,$b){
$this->aa = $a;
}
function aaa(){
echo $this->aa;//this调用构造函数中的变量
}
}
class B extends construct{
public function __construct()
{
echo 'B中的构造方法!';
parent::__construct(100,2);//调用父类的构造方法
}
}
$a = new B() ;
var_dump ($a);
三个关键字 public protected private
修饰符就是用来表明 这个属性或者方法的 可访问成都的关键词
public 公有 谁都可以访问 类似var var是public的同义词 但是var只能修饰属性 public 可以修饰方法和属性
private 私有 只有自己才可以访问
protected 保护 只有相关继承的类可以访问 a继承b B继承c ABC都可以访问
class con {
public $a = '';
private $b = '';
protected $c = '';
function __construct($a,$b,$c)
{
$this->a = $a;
$this->b = $b;
$this->c = $c;
}
}
设计一个工厂类 可以接收一个参数 该参数代表某个类名 比如B 然后这个工厂类就可以生产出传过来的类B的对应的对象
class A{}
class B{}
//用来生产各种类的对象 因为类只是直接调用方法别无他用 因此用静态方法
class factory{
static function GetObject( $class_name){
$obj = new $class_name();
return $obj;
}
}
$a = factory::GetObject('A');
$b = factory::GetObject('B');
var_dump($a);
var_dump($b);
在类中的一个方法 在一个对象被销毁后 会自动调用的方法
方法名 destructor
不能带参数对象什么时候被销毁:代码执行结束被销毁或一个对象没有变量引用它的时候
class destructor{
public function __destruct()
{
echo 111;
}
}
$a = new destructor();
$a = new destructor();
$a = new destructor();
$a = new destructor();
A类使用了B类的属性和方法 说明A继承了B
派生
A继承了B 也就是说 B派生出了A
父类 子类
父是基类 也就是上一级的类
子是继承类 派生类 下一级的类
单继承:
一个类只能从上一级的类继承他的信息 php大部分的面向对象都是单继承
class animal {
public function a (){
echo 'aaa';
}
}
class duck extends animal{
public function b(){
echo 'bbb';
}
}
$q = new duck();
var_dump($q->a());//调用duck继承的类里面的a方法
var_dump($q->b());//调用duck的里面的b方法
定义一个类 并预先设定好 不允许别的类来继承 也就是没有后代
最终类:final 类{}
最终方法 final 访问控制修饰符(可有可无) function 方法名(){}
final class A{
final public function a(){
}
}
class b{
final public function a(){
}
}
子类重新定义父类继承给自己的属性或方法
基本特征是:父类已经有的属性或者方法 子类用同样的名字重新定义 参数不能减少 必须和父类一致
对于构造方法 没有参数的要求
重写也叫覆盖
重写的原因:一般来说 子类的特征信息的定义 一般比父类更详尽
父类没有的 子类可以有 例如添加特征信息
父类有的 子类也可以有 但是子类可以最定义得更加详细
重写的要求:
父类是 public 子类只能是public
父类是 protected 子类只能是 protected public
父类是 private 子类不能重写覆盖
class Animal {
public $blood = 0;
public function eat(){
echo '动物类的吃';
$this->blood+=1;
}
}
class pig extends Animal{
public $blood = 1;//属性重写
public function eat(){//方法重写
echo '猪的吃';
$this->blood+=2;
}
}
class duck extends Animal{
public $blood = 2;//属性重写
public function eat(){//方法重写
echo '鸭子的吃';
$this->blood+=3;
}
}
class A{
public $name = '';
protected $age = '';
private $sex = '';
}
class B extends A{
public $name = '1';
protected $age = '1';
private $sex = '1';
}
$b = new B();
echo '';
var_dump($b);
用在子类中 访问父类的方法或属性
用法:parent::属性或方法或父类名字::属性或方法
class A {
public $name ='';
public $age ='';
public $sex ='';
public function __construct($name,$age,$sex){
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
}
class B extends A{
//接受参数
public function __construct($name,$age,$sex)
{
//调用父类的构造方法 两种方法 一种是直接类名 一种是parent
A::__construct('1','2','3');
parent::__construct('4','5','6');
}
}
$a = new B('ZZS','','');
var_dump($a) ;
多次调用 只能实例化同一个对象
不会重复
class single{
//定义一个私有的静态属性用来装一个对象 外界无法访问
private static $s = null;
//私有构造方法 不让外界new对象
private function __construct()
{
}
//给外界提供一个方法 让他从这个方法来获得一个对象
static function Getone(){
if(empty(self::$s)){//如果还没被实例过
self::$s = new self();
return self::$s;
}else{
//否则就直接返回刚才的对象
return self::$s;
}
}
}
$obj = single::Getone();
$obj1 = single::Getone();
var_dump($obj);
var_dump($obj1);
所谓的静态 就是只属于这个类的属性和方法
类中的属性名和方法名 用static
写法:
static $属性名
static function
使用:
类名::$属性名
类名::方法名
class Math{
static $a = 0;
static function b ($x,$y){
$q = $x * $x + $y*$y;
return pow($q,0.5);
}
}
$aaaa = Math::$a;//调用类中的静态属性
var_dump($aaaa);
$vvv = Math::b(2,2);//调用类中的静态方法
var_dump($vvv);
$this 代表调用当前方法的对象
只能用于在一个类定义语法的内部 通常不在静态方法中(无法使用)
self 代表当前单词所在的类的本身 既可以用在静态方法中 也可以用在普通方法中
只能用于在一个类定义语法的内部
class total {
static $a = '1';
var $b = '2';
function b_f(){
echo 'b_f';
var_dump($this->b);//类中用this调用属性
var_dump(self::$a);//类中用self调用静态属性
}
static function a_f(){
echo 'a_f';
var_dump(self::$a);//类中用self调用静态属性
// var_dump($this->b);//类中用$this调用属性 会报错
}
}
$t = new total();
var_dump($t->b_f());//调用方法
$t->b;//调用b属性
total::$a;//调用静态属性
total::a_f();//调用静态方法
var_dump(total::a_f());//调用静态方法
一个不能被实例化的类
abstract 类名
抽象方法 什么也不做的方法 基本上跟抽象类一起使用 没有方法体 只有方法头
abstract function 方法名(形参1,形参2)
抽象类和抽象方法的关系
一个类中有抽象方法 该类就是抽象类
一个抽象类中可以没有抽象方法
子类继承于一个抽象类
要么子类必须实现父类中的所有抽象方法
要么子类也做抽象类,此时可以不实现父类的抽象方法 当然去实现也可以
子类实现抽象父类的方法 访问控制修饰符的范围不能降低 且方法的参数必须一致 相当于重写
abstract class Animal {
protected $blood = 100;
function Attack(){
echo '发动攻击';
$this->blood--;
}
abstract function a();
}
class tiger extends Animal{
function Attack()
{
echo '老虎发动攻击';
$this->blood-=2;
}
}
class fish extends Animal{
function Attack()
{
echo '鱼发动攻击';
$this->blood-=1;
}
}
是比抽象类更抽象的类似的一种结构
接口中 只有这两种成员 常量和抽象方法
接口类中的方法都是抽象类 但是不需要用 abstract这个关键字来声明
为什么需要接口
面向对象的单继承是对‘现实世界’的多继承现象的一种妥协 为了不使代码过于复杂
但有时候 又往往需要多继承的情形需要描述
于是 使用接口这种技术 可以做到多继承
接口中的常量和抽象方法 都只能是public 而且不用写
抽象方法 无需使用abstract
对接口的继承 不叫 extends 而叫实现 implements
class 类 implements 接口1,接口2,接口3{
}
interface Player{
function play();
function next();
function prev();
function stop();
}
interface Usb{
const width = 12;
const heigt = 5;
function data_in();
function data_out();
}
//zzs 实现 以上两个接口中的抽象方法
class zzs implements Player,Usb{
function play(){}
function next(){}
function prev(){}
function stop(){}
function data_in(){}
function data_out(){}
}
/**
* 另外
* 一个类 也可以继承其他类 并同时实现 其他接口
*/
class A extends B implements Player,Usb{
}
//接口之间也可以进行继承 可以实现多继承
interface zz extends Player,Usb{
}
方法重载 当对一个未定义的方法进行调用的时候 会自动调用 预先设定的好的魔术方法
使用一个对象或者类的时候 如果访问了其并没有定义的(即不存在的)的属性或方法
则会使用某些预先定义好的特殊方法来应对这种情况
是一种应对非法使用对象或类的措施
__call()
当对一个对象未定义的实例方法进行调用的时候 会自动调用预先定义好的魔术方法
__callstatic()
当对一个对象未定义的静态方法进行调用的时候 会自动调用预先定义好的静态魔术方法
class A{
public function a1(){
echo 'a1实例方法';
}
//第一个参数表示不存在的方法名字
//第二个参数表示调用不存在的方法时的所有实参 是一个数组 array
function __call($name, $arguments)
{
var_dump($name);//输出调用不存在的方法的名字
var_dump($arguments);//输出调用不存在方法的时候 传的参数 并装成一个数组
if($name == 'eat'){
$num = count($arguments);
if($num == 1){//调用喝粥方法
$this->hezhou($arguments[0]);
}else{
$this->chifan($arguments[0],$arguments[1]);
}
}
}
function hezhou($p1){
echo '一口吃完'.$p1;
}
function chifan($p1,$p2){
echo '使用'.$p2.'一口吃完'.$p1;
}
//静态魔术方法
static function __callStatic($name, $arguments)
{
}
}
$a = new A();
var_dump($a->a1());
var_dump($a->a12('1','2','3'));
$a->eat('1');
属性重载 在定义一个类的时候 预先定义4个方法,来应对使用不存在的属性的时候的措施
使用一个对象或者类的时候 如果访问了其并没有定义的(即不存在的)的属性或方法
则会使用某些预先定义好的特殊方法来应对这种情况
是一种应对非法使用对象或类的措施
__set($name,$value)方法
对一个对象不存在的属性进行赋值的时候 会自动被调用
__get($name,$value)方法
对一个对象不存在的属性进行取值的时候 会自动被调用
__isset($name)方法
对一个对象不存在的属性进行isset()判断 会被自动调用
__unset($name)方法
对一个不存在的属性进行unset的时候 会自动调用
class Al{
public $p1 = 1;
//创建空数组 用来存储那些不存在的属性的赋值
public $prop_list = array();
function __set($name, $value){
// echo '不存在!'.$name.'=>'.$value;
$this->prop_list[$name] = $value;
echo '';
var_dump($this->prop_list);
}
function __get($name){//$name代表取值的不存在的属性
if( !empty($this->prop_list[$name]) ){
return $this->prop_list[$name];
}else{
return '属性不存在!';
}
}
function __isset($name)
{
if(isset($this->prop_list[$name])){//如果确实存在 返回真
return true;
}else{
return false;
}
}
function __unset($name)
{
unset($this->prop_list[$name]);
}
}
$a = new Al();
$a ->p1 = 2;//对一个存在的属性进行赋值
$a ->p2 = 11;//对一个不存在的属性进行赋值
$a->p1;//对一个存在的属性进行取值
var_dump($a->p2);//对一个不存在的属性进行取值
var_dump(isset($a->p1));
unset($a ->p3);
var_dump($a->prop_list);
当使用一个类 而这个类不存在的时候 就会去调用某个函数
在该函数中可以去加载要加载的类文件
以实现这个类的自动加载
自动加载的注意事项
通常我们将类文件取名为跟类名相关的有规律性的名字 类名.class.php
这个类文件中 只包含一个类的定义语句 不要有其他
类文件要集中放在一个文件夹中
//这个函数在后续代码中只要需要一个类 就会自动被调用 进行自动加载
//唯一参数 表示要找的类名
function __autoload($class_name){
echo '没有这个类';
require_once './'.$class_name.'.class.php';
}
$a = new zzs();
var_dump($a);
新对象 = clone 旧对象
class A{
public $na = 'zzs';
}
$a = new A();
$b = clone $a;
var_dump($a);//1号对象
var_dump($b);//2号对象
只能遍历可访问的属性
class A{
public $p1 = 2;
protected $p2 = 3;
private $p3 = 4;
static $p4 = 5;
//用来显示对象的所有属性
function showAll(){
foreach($this as $prop => $value){
echo "
";
}
}
}
$a = new A();
//遍历该对象 会一次次的获取该对象的属性
//并将属性名赋值给$prop 属性值赋值给value
foreach($a as $prop => $value){
echo "
";
}
$a->showAll();
var_dump($a);
对象在进行序列化的时候 会自动调用类中的魔术方法 __sleep() 前提有这个方法
对象在进行反序列化的时候 会自动调用类中的魔术方法 __wakeup() 前提有这个方法
对于对象的序列化 如果__sleep()方法 此时w我们就可以人为控制序列化的细节
在这个方法中必须返回一个数组 该数组存储了该对象要进行序列化的属性名
也就是 序列化的时候 可以选择哪些属性序列化
//举例 设计一个类 有三个属性 并实例化一个对象
//将这个对象进行序列化 并控制只序列化其中两个属性
//然后在反序列 进行观察
class time{
public $n1 = 1;
public $n2 = 2;
public $n3 = 3;
function __sleep(){//进行序列化的时候 会调用到的方法 __sleep()
//希望对象只序列化 n1 n3
return array("n1","n3");
}
}
$t = new time();
$t->n1 = 11;
$t->n2 = 22;
$t->n3 = 33;
//将这个对象进行序列化
$str = serialize($t);
//写入文件
file_put_contents('./ob.txt',$str);
//反序列化
$zz = file_get_contents('./ob.txt');
$res = unserialize($zz);
var_dump($res);
与类相关的函数
class_exists() 判断某个类是否存在
interface_exists() 判断某个接口是否存在
get_class($对象) 获得一个对象的所属类
get_parent_class($对象) 获得一个对象的所属类的父类
get_class_methods(类名) 获得一个类的的所有方法名 结果是一个数组
get_class_vars(类名) 获得一个类的所有属性名 结果是一个数组
get_declared_classes() 获得所有类名
与对象有管的系统函数
is_object() 判断是否是对象类型
get_object_vars($对象) 获得一个对象的所有属性 不包含静态属性
与类相关的运算符
new 创建一个类的对象(实例)
instanceof 判断一个对象(变量) 是否是某个类的对象
class A{
function f1(){
echo '当前这个类'.__CLASS__;
echo '当前方法为'.__METHOD__;
echo '当前目录'.__DIR__;
echo '当前文件'.__FILE__;
echo '当前行为'.__LINE__;
}
}
$a = new A();
var_dump($a->f1());
//instanceof 判断一个对象(变量) 是否是某个类的对象 是返回true 否返回false
//演示
class hh {
}
class hao extends hh{
}
$v1 = 1;
$v2 = new hh();
$v3 = new hao();
$res = $v1 instanceof hh;//v1不是hh的对象 所以 返回false
var_dump($res);
class A{
public $name = 'zz';
protected $age = 22;
//当对象被当作字符串来使用的时候 进行调用
function __toString()
{
echo "对象被当作字符串来使用";
}
}
class B{
function __invoke()
{
echo '我是一个对象 不要当我是函数';
}
}
$b = new B();
//将对象当作函数来使用
$b();
对象转对象 没有变化
数组转对象 键名当作属性名 值为对应值 整数下标的单元 转换为对象的属性后 无法操作
null转换为对象 空对象
其他标量数据转换为对象 属性名为固定的‘scalar’ 值为该变量的值
$s = new stdClass();
$conf = array(
'host'=>'localhost',
'user'=>'root',
'pass'=>'root'
);
$c = (object)$conf;//强制类型转换 数组转对象
var_dump($c);
/***其他标量数据转换为对象 */ //属性名都是 scalar
$v1 = 2; $v1c = (object)$v1;//整型转对象
$v2 = 2.2; $v2c = (object)$v2; //浮点转对象
$v3 = "abc"; $v3c = (object)$v3; //字符串转对象
$v4 = true; $v4c = (object)$v4; //布尔型转对象
echo '';
var_dump($v1c);
var_dump($v2c);
var_dump($v3c);
var_dump($v4c);
只能在函数或方法的形参上进行约束
只能对数组 对象 类和接口进行约束
数组:使用array关键字
类:使用要求传递过来的实参对象必须是该类的对象
接口:要求传递过来的实参对象必须是实现了该接口的对象
class A{
public function nam(){
echo '111';
}
}
interface I1{}
class b implements I1{}
function f1($p1,Array $p2,A $p3, I1 $p4){
//此时 p1没有约束 p2必须是传过来的是数组
//p3必须是类A的对象
//p4必须是实现了接口 I1的对象
}
//实例化
$a = new A();
$b = new b();
//调用函数
// f1(1,2,3,4);//此时不满足约束 会报错 从第二个参数开始报错 表示第二个参数必须是数组
// f1(1,array(
// 'host'=>'1111','sss'=>'2222'
// ),3,4);//此时不满足约束 会报错 must be an instance of A 表示必须是A的实例(也就是A被实例化的对象)
f1(1,array(
'host'=>'1111','sss'=>'2222'
),$a,$b);//此时报错第四个参数 must implement interface I1 必须是实现接口I1的对象 (也就是继承实现I1的类)
序列化:将一个内存形态存在的变量的非持久数据 转换成硬盘形态存在的物理数据的过程
反序列化:将之前序列化之后的硬盘形态存在的物理数据 恢复为序列化之前的内存形态存在的变量数据的过程
变量数据序列化的过程分为两步:
将变量的serialize()函数进行处理 获得字符串结果 $str = serialize($v1) $v1是一个变量 自然也是一个数据
将字符串结果 保存为文件到硬盘中 file_put_contents("文件路径",$str)
磁盘数据反序列化的过程分为两步:
从文件中读取序列化的结果 $str = file_get_content('文件路径');
将字符串使用unserialize()j进行处理 获得原始数据 $v1 = unserialize($str)
//演示序列化
$v1 = 1; $str1 = serialize($v1);
$v2 = 2.2; $str2 = serialize($v2);
$v3 = "acaca"; $str3 = serialize($v3);
$v4 = true; $str4 = serialize($v4);
$v5 = array(51,53,45); $str5 = serialize($v5);
//将结果 写入并创建到一个文件中
file_put_contents('../record1.txt',$str1);//i:1;
file_put_contents('../record2.txt',$str2);//d:2.2
file_put_contents('../record3.txt',$str3);//s:5:"acaca"
file_put_contents('../record4.txt',$str4);//b:1
file_put_contents('../record5.txt',$str5);//a:3:{i:0;i:51;i:1;i:53;i:2;i:45;}
//演示反序列化
$str1 = file_get_contents('../record1.txt');$v1 = unserialize($str1);
$str2 = file_get_contents('../record2.txt');$v2 = unserialize($str2);
$str3 = file_get_contents('../record3.txt');$v3 = unserialize($str3);
$str4 = file_get_contents('../record4.txt');$v4 = unserialize($str4);
$str5 = file_get_contents('../record5.txt');$v5 = unserialize($str5);
var_dump($v1);
var_dump($v2);
var_dump($v3);
var_dump($v4);
var_dump($v5);
关于对象的相关知识就整理到这里,觉得有用的加个关注点个赞哦!