接口、抽象类、实现类这三者有什么联系和区别?
接口:更高级的抽象类,不可以定义变量,可以定义常量
抽象类:介于实现类与接口之间的一个中间层 ,既可以定义变量、也可以定义常量
实现类:就是 implements 或 extends 接口或抽象类以后的类文件
结果:常量在接口中是不可以被复写的,接口中不允许定义变量。
那么说说我对接口中不能定义变量的理解,因为在接口中的所有方法都是抽象的,没有实现,没有办法去修改这个变量值的方法。
大家说,谁实现这个接口,谁去实现这个方法,不就可以了,其实上这么做,按照道理来说是可以的,但是语法是不支持这样做的,会报错。
其实如果完全就是要这样做,可以使用抽象类去完成这样的工作就可以了啊,即能完成变量的定义,也能定义变量。
通俗的讲,你认为是要变化的东西,就放在你自己的实现中,不能放在接口中去,接口只是对一类事物的属性和行为更高层次的抽象。
对修改关闭,对扩展(不同的实现 implements)开放,接口是对开闭原则的一种体现。
代码演示:
bIn.phpinterface bIn{
const table='interface 中的 bIn 表';
public function add();
public function del();
public function edit();
public function find();
}
c.phpinclude_once 'bIn.php';
class c implements bIn{
const table='c 表';
public $ff='';
public function add()
{
echo 'c---add
';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();
现在通过浏览器去运行:
注意,我们复写了接口中的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.phpclass V{
const table='v 中的 V 表';
const Header=[
'name'=>'jim',
'age'=>17,
'city'=>'beijing'
];
}
testV.phpinclude "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.phpinclude "V.php";
class testV extends V{
const table='testV 中的 V 表';
const Header=[
'name'=>'jim',
'sex'=>'n'
];
}
echo testV::table;
print_r(testV::Header);
echo "
";
$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.phpinclude "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 "
";
$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;