<?php
use PhpOffice\PhpSpreadsheet\Calculation\Engineering\Compare;
/**
* 访问控制
* public 公有
* private 私有 只能在类内部使用
* protected
* 类的属性和方法
* this 类的一个实例
* 类常量
* ----继承----
* 当父类的方法是私有的private的时候,子类是不能调用的,内部是可以访问的
* 当父类的方法是受保护的protected的时候,子类是可以访问的
* 当子类的方法与父类的方法相同的时候, 子类覆盖父类方法
* 当子类没有构造方法时, 直接调用父类的构造方法
* 当子类和父类都有构造方法时, 子类调用其本身的构造方法,当想调用父类的构造方法时使用:parent::construct();
* ---final 关键字---
* final class Dad {} 类加上final 关键字后, 类不能被继承
* final function Name(){} 父类的方法加上final关键字后,该方法在子类时不能被重写的
* --- 命名空间---
* namespace venter\session
* namespace test
* ---define----
* define 定义常量是全局的
* --- const 定义常量----
* ---自动加载类 autoload 用的少 基本都在使用 spl_autoload_register()----
* ---static 关键字---
* 当属性和方法被定义为static的时候, 这个属性和方法就属于类的属性和方法, 可以直接调用, 不需要实例化
* ----对象复制---
* 在php中对象的拷贝是浅拷贝, 改变地址
*
* --- 接口---
* 接口是类的模板,类是对象的模板
* interface Person{
* }
*
**/
class Computer{
//属性
public $cpu=5000;
public $mainboard ='huashuo';
private $ht="512";
const ONE =1;
const TWO= self::ONE+1;
const THREE = self::TWO+1;
//构造方法 实例化的时候调用
public function __construct()
{
}
function __autoload($name){
require $name.".php";
}
//方法
public function game($gamename){
if($this->hdSize<1024){
echo '内存太小';
return false;
}
return true;
}
public function job($jobName='write code'){
$this->game("ddd");
}
public function hdSize(){
$this->ht;
}
//析构方法
public function __destruct()
{
}
}
// var_dump(Computer::THREE);
// $computer = new Computer();
// $computer->job();
class Person{
public static $hand ="手";
public static $foot = "脚";
static function getCount(){
return self::$foot;
}
}
echo Person::getCount();
class A{
public static function who(){
echo "A类的方法";
}
public static function test(){
//self::who() ; //父类本身的who方法
static::who(); // static 自动判断,是类A还是类B, 后期绑定
}
}
class B extends A{
public static function who(){
echo "B类的方法";
}
}
echo B::test(); // 此时输出 “B类的方法”
class Test{
private $abc="";
public $testi;
public function __set($var,$val){
$this->var=$val;
}
public function __get($var){
return $this->var;
}
//调用的方法不存在时, 不会报错 两个参数, 一个方法名, 一个参数名
public function __call($func,$var){
var_dump($var) ;
}
//静态方法未定时,调用不会报错 $test::goes("r","d","4");
public static function __callStatic($name, $arguments)
{
var_dump($arguments);
}
public function __toString(){
return $this->test;
}
}
$test = new Test();
$test->abc ='abcsss';
$test->go("q","d","dd"); //已数组的方式传参数 go方法没有定义,不会报错
$test::goes("r","d","4"); // 该方法未定义直接调用, 不会报错,
echo $test; //echo 输出对象不会报错, 因为定义了 __toString()魔术方法
var_dump($test->abc);
//接口-----------------------------------------------------------
interface Persons{
public function eat();
public function sleep();
}
class Woman implements Persons{
public function eat(){
echo "eat fruit";
}
public function sleep(){
echo 'sleep early';
}
}
class Man implements Persons{
public function eat(){
echo "eat fruit less";
}
public function sleep(){
echo 'stay up';
}
}
class L {
public static function factory(Persons $user){
return $user;
}
}
$result = L::factory(new Man());
$result->eat();
$result->sleep();
//接口 继承--------------------------------------------------------------------------
interface ai{
const abc="hhhh";
public function a();
}
interface bi{
public function b();
}
interface ab extends ai,bi{
}
class Test4 implements ab{
public function a(){
echo "aaaaaaaaa";
}
public function b(){
echo "bbbbbbb";
}
}
$dd = new Test4();
$dd->a();
$dd->b();
echo (ai::abc);
// 抽象类abstract、
abstract class ABC {
public function holiday(){
echo "wait";
}
public function sleep(){
}
public function eat(){
}
}
class ABB extends ABC{
public function sleep(){
echo "Yes";
}
public function eat(){
$this->holiday();
echo "No";
}
}
$aaa = new ABB();
$aaa->eat();
$aaa->sleep();
//------单例模式和工厂模式----------
//单例模式确保类只能有一个实例 节省空间
class TestAB{
private static $_instance =null;
private function __construct()
{
}
private function __clone(){
}
public static function getInstance(){
if(!(self::$_instance instanceof self)){
self::$_instance =new self();
}
return self::$_instance;
}
}
$nn = TestAB::getInstance();//实例化两次,但是只开辟一次空间 两个变量值相同
$nn2 = TestAB::getInstance();
print_r($nn) ;
print_r($nn2) ;
//------- 工厂模式
//
class Memcache{
public function set(){
}
public function get(){
}
public function delete(){
}
}
class Cache{
public static function factory(){
// 文档中多数运用Memcache类时, 假如因为当前需要,改为redis ,需要使用工厂模式
return new Memcache();
}
}
//直接把Memcache 替换为redis 即可, 其他代码部分不需要更改
$cache = cache::factory();
$cache->set();
在php中继承的特点是只支持单继承,即一个子类只能继承一个父类, 去获得父类中的方法。但从php5.4开始有trait概念,一个类可以通过use关键字引入多个trait的方法,用trait解决了单继承的问题。
类型约束有int,string,array,float,bool等。但类也可以作为类型约束的类型之一,如图test(A $a)指的是$a必须是类A的对象,否则会报错。
浅拷贝:对象赋值$b=$a,2个对象指向同一块内存地址,值发生改变会互相影响。浅拷贝比较省内存。
深拷贝:用clone关键字,会产生一块新的内存存储对象。clone后相当于有两个值相同的不同的对象。若clone的原对象里有对象属性如$a->obj,由于对象复制默认是浅拷贝,则要用到__clone魔术方法定义对象属性为深拷贝。这样$a->obj->sex才不受$b->obj->sex影响。
self::who()和static::who()的区别在于self指的本类,即父类A,而static会根据代码实际情况判断指的是B类。
static关键字
当属性和方法加上static关键字后,属性和方法就是类的,可以直接通过类名进行调用,无需实例化。么 当给一个属性加上static关键字,那么这个属性变成了类属性,不需要实例化类(获得对象)就可以直接用类名进行调用。如Person::$foot;方法同理如Person::work();
命名空间+类名 = 类文件路径.
用spl_autoload_register()替换字符串后自动加载类文件
命名空间和全局空间
1. 在全局空间中引用命名空间的类,用use关键字引入命名空间的类,as起别名。若引入函数则为use function venter\session\iLikeImooc;引入常量则为use const venter\IMOOC;
2.在命名空间中引用全局空间的类,若为namespace venter,即命名空间为venter,如new Test();类默认为venter\Test();找不到会报错,在类前加反斜杠new \Test();则为找到全局空间的Test类。函数和常量会先在命名空间中找,找不到会去全局找。
外部想要对私有属性进行读取和修改。
<?php class Test { private $abc = ''; public function setAbc($val) //修改 { $this->abc = $val; } public function getAbc() //读取 { return $this->abc; } } $test = new Test(); $test = setAbc('hahaha'); //hahaha赋给参数$val var_dump($test->getAbc()); //打印出:string(6)"hahaha"
若有多个私有属性要被外部访问,上述就不行了,所以有了两个魔术方法:__set 和 __get 。如:
<?php class Test { private $abc = ''; private $cba = ''; public function __set($var,$val) //修改。 __set(属性名,属性值) { $this->$var = $val; } public function __get($var) //读取。 __get(属性名) { return $this->$var; } } $test = new Test(); $test->abc = 'hahaha'; //当给私有属性赋值时,会默认自动地调用__set方法,如果类里没有__set方法,就会报错 var_dump($test->abc); //打印出:string(6)"hahaha"
魔术方法 __isset 用于检测私有属性是否存在。
<?php class Test { private $abc = 'abc'; public function __isset($var) { return isset($this->$var)?true:false; } } $test = new Test(); var_dump(isset($test->abc)); //打印出:bool(true)
魔术方法__unset 删除
<?php class Test { private $abc = 'aaa'; public function __unset($var) { unset($this->$var); } } $test = new Test(); unset($test->abc);
为避免要调用的方法不存在,用魔术方法 __call 当被调用的方法不存在时,__call 会自动被调用。如:
<?php class Test { public function __call($func,$arguments) //__call(方法名,参数) { echo($func . "<br/>"); print_r($arguments); } } $test = new Test(); $test->go(1,'ok'); //结果为:go // Array( [0] =>1 [1] => ok )
当静态方法不存在时,魔术方法__callStatic 会被自动调用。如:
<?php class Test { public static function __callStatic($method,$arg) //要加static关键字 __callStatic(方法名,参数) { echo($method . "<br/>"); print_r($arg); } } Test::go(1,'ok'); //结果为:go // Array( [0] =>1 [1] => ok )
当对象以函数的方式被调用时,魔术方法__invoke会自动被调用。
<?php class Test { public function __invoke($arg) { var_dump($arg); } } $test = new Test(); $test('go....'); //这就是对象以函数的方式被调用 结果为:string(6)"go...."
当对象被打印时,魔术方法__toString() 会自动被调用。
<?php class Test { public function __toString() { return "hello....."; } } $test = new Test(); echo($test); //结果为:hello......
<?php class A { public static function who() { echo "AAA"; } public static function test() { static::who(); //之后的结果为BBB,若用self::who(),则结果为AAA } //因为子类B调用父类的test方法,又调用who方法,子类父类都有who方法,用static是调用子类的who方法,用self是调用父类(也就是self所在类的)who方法 } //子类 class B extends A { public static function who() { echo "BBB"; } } B::test(); //因为这里是B,所以父类A和子类B都有who方法我们也要调用子类B的who方法,
imooc.php:
<?php class Imooc { public function nice() { echo "imooc nice"; } }
main.php:
<?php function __autoload($className) //__autoload()是内置函数,实现类的自动加载 { require $className . ".php"; } $imooc = new Imooc(); var_dump($imooc); //结果为:object(Imooc)#1(0){} //__autoload()函数将在以后PHP版本里不再使用,所以用spl_autoload_register()函数 <?php spl_autoload_register(function($className){ require $className . ".php"; }); $imooc = new Imooc(); var_dump($imooc); //结果为:object(Imooc)#1(0){} //还可以: <?php function test($className){ require $className . ".php"; } spl_autoload_register('test'); $imooc = new Imooc(); var_dump($imooc); //结果为:object(Imooc)#1(0){} //若在类里: <?php class Momo { function haha($className) { require $className . ".php"; } } spl_autoload_register([new Momo,'haha']); $imooc = new Imooc(); var_dump($imooc); //结果为:object(Imooc)#1(0){}
现文件级别如下:
main.php:
<?php spl_autoload_register(function($className){ include str_replace("\\","/",$className .".php"); //将\转换为/, (两个\\因为其中一个\是转义字符)将在网页上显示models/Imooc,为了显示出路径 }); $imooc = new models\Imooc(); var_dump($imooc); //结果为:object(models/Imooc)#2(0){}
Static关键字:
当给属性加上Static关键字,该属性就是类的属性,而不是对象的,不用实例化这个类,就可以通过类名调用。方法也是可以。如:
<?php class Person { public static $hand = "手"; public static $foot = "脚"; public static function work() { return "单纯的工作"; } } echo(Person::$foot); echo(Person::work());
<?php class Person { public $a = 1; public static function work() { echo ($this->$a); //有static关键字时不能这样,会报错。$this代表的是对象,self是代表的是类 return "单纯的工作"; } } echo(Person::work()); //会报错 <?php class Person { public static $hand = "手"; public static $foot = "脚"; public static function work() { echo(self::$hand); //因为是类的方法和属性,不是对象的,所以用self return "单纯的工作"; } } echo(Person::work()); //结果为:手单纯的工作 //子类 class Imooc extends Person { public function play() { parent::work(); //parent代表类 } } $imooc = new Imooc(); echo($imooc->play()); //结果为:手单纯的工作
两个类的类名相同,会出现错误。 所以引入了命名空间。
和文件中的目录一样,同一目录不存在相同命名的文件,而不同目录存在相同命名的文件。 命名空间借鉴了这种方法。
php:
<?php namespace venter; //用namespace关键字,Imooc类和iLikeImooc()函数和IMOOC常量就在venter命名空间下 class Imooc { } function iLikeImooc(){ echo "i Like imooc"; } //曾经用define()定义一个常量,这个不受命名空间影响,所以用const定义常量 const IMOOC = 'nice';
2.php:
<?php namespace venter\session; //用\表示session是venter下一级, class Imooc { }
main.php:
<?php include '1.php'; include '2.php'; var_dump(new venter\Imooc()); var_dump(new venter\session\Imooc()); //两个同名类就都可打印了 venter\iLikeImooc(); //两个同名函数就可调用了 echo(venter\IMOOC); //同名常量都可打印出来了
还可以这样:
main.php:
<?php include '1.php'; include '2.php'; use venter\session\Imooc; var_dump(new Imooc()); //就不需要这样一大串var_dump(new venter\session\Imooc()); use venter\Imooc as Imooc2; //另一同名类用as取名为Imooc2 var_dump(new Imooc2()); use function venter\iLikeImooc; //函数,use后需要有function ,能加as命名 iLikeImooc(); use const venter\IMOOC; //常量,use后要有const var_dump(IMOOC);
当没有使用namespace来指定当前脚本的命名空间时,则当前脚本存在于全局命名空间。命名空间分两个,一个是有被指定,一个没有指定。
3.php:
<?php class Test1 { } function Text2() { } const TEST3 = 'test3';
index.php:
<?php namespace index; include '3.php'; var_dump(new \Text1()); //在此脚本文件有命名空间下,会找此命名空间的类, //若是var_dump(new Text1())因为Text1是3.php是全局空间的类,就会报错,找不到类。所以Text1前加\ Test2(); //函数和常量在此命名空间下若没有,会自动在全局空间3.php里找,而类不自动去全局空间找,所以要加\ echo(TEST3);
被继承的类叫父类。子类继承父类的属性和方法。通过子类扩展了父类的功能,是之前所学的扩展性。
<?php class Dad { public function Kungfu() { echo "降龙十八掌"; } } class Boy extends Dad //使用 extends 关键字使子类继承父类 { } $boy = new Boy(); $boy->Kungfu(); //结果为:降龙十八掌 (子类继承父类的属性和方法)
当父类的方法是私有的(private),子类不能调用,只有父类本身类的内部能用。
当父类的方法是受保护的(protected),只能被父类自己和继承的子类调用,其他类和外部不能调用。
方法名相同时,子类的方法覆盖父类的方法:
<?php class Dad { public function Kungfu() { echo "降龙十八掌"; } } class Boy extends Dad { public function Kungfu() //方法名相同时,子类的方法覆盖父类的方法: { echo "凌波微步无影掌"; } } $boy = new Boy(); $boy->Kungfu(); //结果为:凌波微步无影掌
当子类没有构造方法时,会自动调用父类的构造方法。
当子类有自己的构造方法时,就调用自己的构造方法,而不会调用父类的构造方法。若既想调用父类的构造方法也有子类的,用 parent 关键字。如:
<?php class Dad { public function __construct() { echo "dad dad..."; } public function Kungfu() { echo "降龙十八掌"; } } class Boy extends Dad { public function __construct() { parent::__construct(); //若既想调用父类的构造方法也有子类的,用 parent 关键字。 echo "boy boy.."; } } $boy = new Boy(); $boy->Kungfu(); //结果为:dad dad...boy boy...降龙十八掌
父类不想被子类继承,用 final 关键字,如:
final class Dad
父类的某个方法不想被子类继承,用 final 关键字,如:
final public function Kongfu()
在实例化一个对象的时候,通常需要初始化。 对象被销毁的时候,需要有回收。所以就用到了类里面的两个内置的方法:构造方法和析构方法。
构造方法:
<?php class Computer{ public function __construct() //内置的构造方法,不用调用直接就会执行 { echo "cpu就绪。。"; echo "主板就绪。。"; echo "内存就绪。。"; } public function game() { echo "---玩游戏---"; } } $computer = new Computer(); $computer->game(); //结果为:cpu就绪。。主板就绪。。内存就绪。。---玩游戏---
<?php class Computer{ public function __construct($high = 0) { if($high){ echo "高配的cpu就绪。。"; echo "高配的主板就绪。。"; echo "高配的内存就绪。。"; }else{ echo "cpu就绪。。"; echo "主板就绪。。"; echo "内存就绪。。"; } } public function game() { echo "---玩游戏---"; } } $computer = new Computer(1); // 1这个参数就是构造方法的参数 $computer->game(); //结果为:高配的cpu就绪。。高配的主板就绪。。高配的内存就绪。。---玩游戏---
析构方法:
<?php class Computer{ public function game() { echo "---玩游戏---"; } public function __destruct() //是析构方法,直接可执行 { echo "关闭电源。。。"; } } $computer = new Computer(); $computer->game(); //结果为:---玩游戏---关闭电源。。。 //还可以这样 手动释放对象变量 unset($computer); echo "good job"; //结果为:---玩游戏---关闭电源。。。good job
类常量:
<?php class Computer { const YES = ture; //const关键字定义类常量,类常量一般是大写字母和下划线组成 const NO = false; const ONE = 1; const TWO = self::ONE + 1; //在类里用self调用类里的常量 const THREE = self::TWO + 1; } var_dump(Computer::THREE); //在类外面可直接调用类里的常量,结果为:int(3)
调用静态方法self:: 与static::的区别
selft代表自身;static可以实现后期绑定
命名空间
例如:namespace venter;
namespace venter\session
调用:命名空间(venter)\ 成员(Imooc())
将类,函数,常量导入命名空间
例如:
use venter\session\Imooc();
use venter\Imooc as Imooc2;
use function venter\iLIkeImooc;
use const venter\Imooc;
命名空间需要调用全局空间定义的类需要添加“\”;而方法或者常量不需要,因为方法或者常量发现在当前命名空间没找到的话,会去全局命名空间找
子类继承父类,如果子类没有构造方法,实例化子类的时候会调用父类的构造方法。如果子类中有构造方法,会调用自身子类的构造方法。如果子类中也想调用父类的构造方法,可以用parent调用
组合和继承?
类常量使用见截图
构造函数必须是public,否则不能创建对象。但是如果设置为private,就可以实现单例模式
对象是类的实例,先有类,才有对象。就像配置单和电脑的关系。
类是一个代码模板
//定义一个类 <?php //类名以字母或下划线开头,后面可跟字母、数字、下划线。 class Computer { //类名一般开头的字母大写,为了清晰。当然也可以用小写。 } $computer = new Computer(); //这个对象赋给了这个变量,这个对象叫做Computer类的一个实例。 var_dump($computer); //打印出:object(Computer)#1(0){}
<?php class Computer { public $cpu = 'amd 5000'; //属性 public $mainboard = '华硕9000x'; //属性 private $hd = 1024; //属性 public function game($gameName='') //方法 { echo $this->hd; //要在类里面调用属性,就用this 可以理解为这个类的一个实例(对象) } //打印出:1024 public function job($work='写代码') //方法 { echo ($this->game()); } } $computer = new Computer(); var_dump($computer); //打印出所有的属性:object(Computer)#1 (3) { ["cpu"]=> string(8) "amd 5000"["mainboard"]=> string(11) "华硕9000x" ["hd":"Computer" :private]=>int(1024)} var_dump($computer->cpu); //调用属性 打印出:string(8)"amd 5000" var_dump($computer->hd); //是私有的,不能给外部对象调用 打印出错 ,只能在类的内部使用。 ?> <?php class Computer { public $cpu = 'amd 5000'; //属性 public $mainboard = '华硕9000x'; //属性 private $hd = 512; //属性 public function game($gameName='') //方法 { if($this->getHdSize() < 1024){ echo "硬盘太小玩不了游戏"; return false; } return true; } public function job($work='写代码') //方法 { echo ($this->game()); //整个的结果就是打印出:硬盘太小玩不了游戏 } public function getHdSize() //方法 { return $this->hd; //获取硬盘大小 } } $computer = new Computer();
面向对象编程 可使项目模块化
重用性:设计的每一个模块都可在项目中重复使用
灵活性:每一个模块都可以很轻松地被替换
扩展性:在现有的模块上添加新功能
面向对象:项目由一个个对象组建而成,每个对象都是独立的,他们各司其职,最后像搭积木一样,将各种组合起来,就实现了一个项目。
类 的复用可直接用:use 类名
对象复制是浅拷贝,会改变对象值,前面加clone,这不会改变原来值。
class A {
public static function who()
{
echo "A类的who方法";
}
public static function test()
{
self::who();//输出A类的who方法
static::who();//后期绑定输出B类的who方法 }
}
class B extends A {
public static function who()
{
echo "B类的who方法";
}
}
$this在当前方法使用
self指向当前类
parent指向父类
<?php
class Person
{
public ststic $hand = "手";
public ststic function work()
{
return "工作";
}
}
echo (Person::$hand);
echo (Person::$work());
//当属性或方法定义为static后,输出时就不需要实例化类了,直接调用
1.
spl_autoload_register( function( $className ){
require $className . '.php';
} )
2.
function autoload( $className ){
require $className . '.php';
}
spl_autoload_register( 'autoload' )
3.方法是在类里面
class Momo{
function autoload( $className ){
require $className . '.php';
}
}
spl_autoload_register( [new Momo, 'autoload' ] )// 第一个参数实例,第二个参数是类的方法
$imooc = new Imooc();
var_dump(#imooc);
命名空间一般对类起作用,方法会自动寻找类名。
类调用 use\venter\session\Imooc;
类重命名 use\venter\Imooc as Imooc2;
方法调用 use function venter\iLikeImooc;
常量使用const: use const venter\IMOOC;