接口、抽象类、实现类这三者有什么联系和区别?
接口:更高级的抽象类,不可以定义变量,可以定义常量
抽象类:介于实现类与接口之间的一个中间层 ,既可以定义变量、也可以定义常量
实现类:就是 implements 或 extends 接口或抽象类以后的类文件
结果:常量在接口中是不可以被复写的,接口中不允许定义变量。
那么说说我对接口中不能定义变量的理解,因为在接口中的所有方法都是抽象的,没有实现,没有办法去修改这个变量值的方法。
大家说,谁实现这个接口,谁去实现这个方法,不就可以了,其实上这么做,按照道理来说是可以的,但是语法是不支持这样做的,会报错。
其实如果完全就是要这样做,可以使用抽象类去完成这样的工作就可以了啊,即能完成变量的定义,也能定义变量。
通俗的讲,你认为是要变化的东西,就放在你自己的实现中,不能放在接口中去,接口只是对一类事物的属性和行为更高层次的抽象。
对修改关闭,对扩展(不同的实现 implements)开放,接口是对开闭原则的一种体现。
代码演示:
bIn.php
interface bIn{ const table='interface 中的 bIn 表'; public function add(); public function del(); public function edit(); public function find(); }
c.php
include_once 'bIn.php'; class c implements bIn{ const table='c 表'; public $ff=''; public function add() { echo 'c---add<br>'; echo bIn::table; // TODO: Implement add() method. } public function del() { // TODO: Implement del() method. } public function edit() { // TODO: Implement edit() method. } public function find() { // TODO: Implement find() method. } } $c=new c(); $c->add();
现在通过浏览器去运行:
http://localhost/c.php
注意,我们复写了接口中的const 常量,那么运行会有什么样的提示:
Fatal error: Cannot inherit previously-inherited or override constant table from interface bIn in E:\phpStudy\WWW\song\c.php on line 10
注意,常量在接口中是不可以被复写的,接口中不允许定义变量。
如若定义,就是这样的提示 Fatal error: Interfaces may not include member variables in E:\phpStudy\WWW\song\bIn.php on line 13
换个场景:
V.php
class V{ const table='v 中的 V 表'; const Header=[ 'name'=>'jim', 'age'=>17, 'city'=>'beijing' ]; }
testV.php
include "V.php"; class testV extends V{ const table='testV 中的 V 表'; const Header=[ 'name'=>'jim', 'sex'=>'n' ]; } echo testV::table; print_r(testV::Header);
运行结果:
testV 中的 V 表
Array ( [name] => jim [sex] => n )
结论:类与类之间的继承关系,是可以修改父类中const的。
但是还有一种结果:
V.php 添加一个send方法,方法主要内容是显示 header的内容
class V{ const table='v 中的 V 表'; public $time='123'; const Header=[ 'name'=>'jim', 'age'=>17, 'city'=>'beijing' ]; public function send(){ print_r(self::Header); } public function viewTime(){ print_r($this->time); } }
testV.php
include "V.php"; class testV extends V{ const table='testV 中的 V 表'; const Header=[ 'name'=>'jim', 'sex'=>'n' ]; } echo testV::table; print_r(testV::Header); echo "<hr>"; $test=new testV(); $test->send();
得到结果:
testV 中的 V 表Array ( [name] => jim [sex] => n )
Array ( [name] => jim [age] => 17 [city] => beijing )
我们看到,打印出的结果还是 v.php中的数据。并没有打印出 jim 和 sex=n的数组。
我们再次改造一下:
testV.php
include "V.php"; class testV extends V{ const table='testV 中的 V 表'; const Header=[ 'name'=>'jim', 'sex'=>'n' ]; public function send(){ print_r(self::Header); } } echo testV::table; print_r(testV::Header); echo "<hr>"; $test=new testV(); $test->send();
如果改成这样,就符合我们的预期了,可以正常显示出jim 和 n 了。
结论:在继承父类或抽象类,常量是可以被复写的。 继承抽象类,必须实现未实现的方法。
其实这里还有一点是错误的,这里做一下澄清,我们上边的代码中,使用静态变量都使用的是
self 这是初始化绑定,如果把父类修改成 static::Header 就能打印出在子类定义的常量。
下面是例子,我们看一下:
class V{ const table='v 中的 V 表'; public $time='123'; const Header=[ 'name'=>'jim', 'age'=>17, 'city'=>'beijing' ]; public function send(){ print_r(self::Header); } public function viewTime(){ print_r($this->time); } } class testV extends V{ const table='testV 中的 V 表'; const Header=[ 'name'=>'jim', 'sex'=>'n' ]; } $test=new testV(); $test->send(); //结果 //Array ( [name] => jim [age] => 17 [city] => beijing )
把V.php中的send方法中 self::Headler 改成 static::Headler
<?php class V{ const table='v 中的 V 表'; public $time='123'; const Header=[ 'name'=>'jim', 'age'=>17, 'city'=>'beijing' ]; public function send(){ print_r(static::Header); } public function viewTime(){ print_r($this->time); } } class testV extends V{ const table='testV 中的 V 表'; const Header=[ 'name'=>'jim', 'sex'=>'n' ]; } $test=new testV(); $test->send(); //结果 //Array ( [name] => jim [sex] => n ) ?>
看到变化了,现在使用的是子类中的Header 常量
static 是惰性加载
抽象类实例:
#Ab.php 这是一个抽象类 abstract class Ab{ const name='ab'; public $dec=''; public function edit(){ echo 'edit'; } public abstract function add(); } #testab.php 实现抽象方法 include_once 'Ab.php'; class testab extends Ab{ const name='bbbbb'; public function add() { // TODO: Implement add() method. } } echo testab::name;
运行结果:bbbbb
很明显,已经被修改过了。但是必须去实现 未写完的抽象方法。
抽象类必须使用 abstract 关键字修饰抽象类
抽象方法必须使用 abstract 关键字修饰抽象方法
下面代码:
<?php /* $data=[1,2,3,4,5,8]; foreach($data as &$v){ echo $v; echo PHP_EOL; } foreach($data as $v){ echo $v; } echo PHP_EOL; echo '------------------'; echo PHP_EOL; $data=[1,2,3,4,5,8]; foreach($data as &$v){ $v=$v; echo $v; echo PHP_EOL; } foreach($data as $v){ echo $v; } echo PHP_EOL; echo '------------------'; echo PHP_EOL; $data=[1,2,3,4,5,8]; foreach($data as &$v){ $v=&$v; echo $v; echo PHP_EOL; } foreach($data as $v){ echo $v; } print_r($data); echo PHP_EOL; echo '---------666666666---------'; echo PHP_EOL; $data=[0=>1,1=>2,2=>3,3=>4,6=>5,8]; foreach($data as &$v){ $v=&$v; echo $v; echo PHP_EOL; } foreach($data as $v){ echo $v; } print_r($data); echo PHP_EOL; echo '---------8888888888888888---------'; */ /* echo PHP_EOL; class ParentModel{ static $a=33; } class SunModel extends ParentModel{ public function __construct($num){ self::$a=55; } public function getuser1(){ return self::$a; } public function getuser2(){ return $this->getuser1(); } } echo ParentModel::$a.PHP_EOL; $sun=new SunModel(1); echo $sun->getuser1().PHP_EOL; echo $sun->getuser2().PHP_EOL; */ //https://www.jb51.net/article/136794.htm class ParentModel{ static $a=33; public function getuser3(){ return self::$a; } } class SunModel extends ParentModel{ public function __construct(){ self::$a=55; } public function getuser1(){ return static::$a; } public function getuser2(){ return $this->getuser1(); } } echo ParentModel::$a.PHP_EOL; $patternModel=new ParentModel(); echo $patternModel->getuser3().PHP_EOL; $sun=new SunModel(); echo $sun->getuser1().PHP_EOL; echo $sun->getuser2().PHP_EOL; abstract class Ab{ const name='ab'; public $dec=''; public function edit(){ echo 'edit'; } public abstract function add(); } class testab extends Ab{ const name='bbbbb'; public function add() { // TODO: Implement add() method. } } echo testab::name;
https://www.jb51.net/article/136794.htm