类的定义和调用
<?php
class Animal{
public $name = "小猫";
public $age = 1;
public $birth ="2000-01-01";
public function eat($name){
echo $name."在吃饭";
}
}
//调用类里面的属性.使用new来调用类
// echo (new Animal)->name;
// echo (new Animal)->age;
echo (new Animal)->name."的生日是:".(new Animal)->birth;
echo PHP_EOL;
//上述方法是使用new来调用类,但是如果类中有很多属性的的话,每一个属性都去new的话就太麻烦,而且每次调用都用new的话对性能也是有一定消耗的.因此可以声明一个变量来接收这个new的调用.
$cat = new Animal;
//这样就可以使用$cat来调用Animal类.
// echo $cat->name;
// echo $cat->age;
echo $cat->name."的年龄是:".$cat->age.$cat->eat("xiaomao");
//可以调用属性,也可以调用方法,调用类中的方法时,如果有指定$name参数,就需要填写相应的内容,否则会报错.如果没有指定参数则可以直接调用.
// echo $cat->eat("i");
?>
$this
<?php
//Animal是类名
//$name是类属性
//"小猫"是类属性值
//eat(){}是类方法.
class Animal{
public $name = "小猫";
public $age = 1;
function eat(){
echo $this->name."在吃饭"; //this代表的是他自身的对象,比如他的对象是$cat那么他就会读小猫的属性,比如他的对象是$dog,那么就会读$dog的属性.
}
}
$cat = new Animal;
echo $cat->eat(); //这里输出了:小猫在吃饭
//上述直接读取了类中的name小猫
//还可以通过外部修改对象的属性和调用Animal类的方法,$cat->name = "小花";
echo PHP_EOL;
$cat->name = "小花";
echo $cat->eat();
echo PHP_EOL;
$dog = new Animal;
$dog->name = "小黑";
$dog->age = 5;
echo $dog->eat(); echo PHP_EOL;
echo $dog->eat().",他今年$dog->age"."岁了";
访问控制
<?php
//访问控制
//关键字:public,private,protected
//public:公有,公有的类成员可以在任何地方被访问:比如说可以在类里面被调用也可以在类外部被调用,也可以被子类继承,即子类可以读取到父类的一些属性和方法.
//protected:受保护,受保护的类成员则可以被其自身以及其子类和父类访问.通俗一点就是:我自家的都可以访问,比如说父亲,我自己,我的后代都可以使用我的东西.
//private:私有,私有的类成员则只能被其定义所在的类访问(自己的).只能自己修改自己,在外部以及父类子类都无权访问.
//可以通过公共的方法来让外部去获取和修改自身的属性值.
/* class Animal{
public $cat_name ="小猫崽";
protected $dog_name ="小狗崽";
private $mouse_name ="小鼠崽";
function eat($animal_name){
echo $this->animal_name."爱吃鱼";
}
}
$cat = new Animal;
$dog = new Animal;
echo $cat->eat("小猫咋");
echo $dog->eat();*/
//但是不管是受保护的还是私有的,只要我们想给别人用,想要给别人看的话,也是有办法的.下面以protected为例
class Animal{
protected $name = "小猫"; //把$name改为私有
public $age = 1;
function eat(){
echo $name."在吃饭";
}
//外部获取方法:声明一个公有的方法,通过这个公有的方法,可以在外部获取这个方法提供的内容.比如这个方法提供了获取name的方法:return $this->name;
public function getName(){
return $this->name;
}
//外部写入方法:和外部获取方法同理,声明一个方法,提供给外部写入.
public function writeName($newName){
$this->name = $newName;//这里提供了外部写入的方法,给出$newName作为外部给出的值,并传递给内部的$name.
}
}
$cat = new Animal;
// echo $cat->getName();
//echo $cat->name; //由于name是受保护的,在外部不能直接获取到内部的受保护的内容.因此直接获取会报错.
$cat->writeName("小猫崽的新名字");
echo $cat->getName();
?>
构造函数和析构函数
<?php
//__construct:构造函数是一种特殊的方法,在创建一个新对象时,他会被自动调用.他可以用来初始化对象的属性或者执行其他必要的操作.没有返回值.
//什么是必要操作,比如想要在想要获取用户的姓名和生日,那么名字和生日就是必要的参数,在获取到必要的参数后要让接收到的名字和生日进行传参的操作就是必要的操作,再比如获取到用户的生日后预设一段计算生日的代码来计算用户的年龄也可以是必要的操作.
//__destruct,析构函数,是一种特殊的方法,他在对象被销毁时自动调用.他可以用来执行一些清理操作,例如释放资源或者关闭数据库连接.当对象不再被引用或脚本结束时,析构函数会被自动调用.
//一般来说析构函数用不到,比如关闭数据库连接,php会自动去关闭一些你用不到的数据,用不到的资源.所以不需要我们专门去写一个方法来关闭数据库.
class Animal{
private $name;
private $birth;
private $age;
private $yearsold;
public function __construct($name,$birth){
$this->name = $name;
$this->birth = $birth;
$day = (time() - strtotime($this->birth))/3600/24; //strtotime()作用:将任何英文文本日期时间描述解析为Unix时间戳,单位是秒.
$this->age = floor($day);
$this->yearsold = floor(($this->age)/365);
}
public function eat(){
echo $this->name."在吃饭";
}
public function getInfo(){
echo "$this->name 的年龄是 $this->age 天,出生日期为$this->birth";
}
public function getAge(){
echo $this->yearsold."岁";
}
}
//调用Animal函数
$cat = new Animal("xiaomao","2020-12-12");
// $cat->name = "xiaomao";
// $cat->birth = "2022-12-12";
echo $cat->getInfo();echo PHP_EOL;
$dog = new Animal("小狗","2000-12-12");
echo $dog ->getInfo().PHP_EOL;
echo $dog->getAge() ;
echo $cat->getAge();
析构函数
<?php
//__destruct,析构函数,是一种特殊的方法,他在对象被销毁时自动调用.他可以用来执行一些清理操作,例如释放资源或者关闭数据库连接.当对象不再被引用或脚本结束时,析构函数会被自动调用.
//一般来说析构函数用不到,比如关闭数据库连接,php会自动去关闭一些你用不到的数据,用不到的资源.所以不需要我们专门去写一个方法来关闭数据库.
class MyClass{
public function say($i){
echo "saying --".$i.",";
}
public function __destruct(){
echo "析构函数被调用,\n";
}
}
//创建对象
$obj = new MyClass();
//执行其他操作
for ($i = 0; $i < 4; $i++){
if($i==3){
unset($obj); //unset的作用:注销,销毁这个对象.
// exit;
}
if($obj){
$obj->say($i); //当i不等于3的时候,会输出相应内容.而当i=3的时候,会报错,因为执行了销毁,因此对象已不存在,此时会报错:PHP Warning: Undefined variable $obj in E:\phpcodes\class&object\5析构函数.php on line 23
}
}
static静态变量和self
<?php
//静态,指的是无需对类进行实例化,就可以直接调用这些属性和方法
//所有对静态变量进行的操作都会对所有对象其作用.
//举例:小猫小狗都听指挥,如吃饭,如果指令发生变化,全部都要听从.
class Animal{
public $name = "小猫崽";
//定义一个静态变量:小懒猫,但是如果要使用这个静态变量,就不能使用$this了
public static $cat = "小懒猫";
public $age =1;
public function eat(){
//echo $this->cat." 在吃饭"; //报错:PHP Notice: Accessing static property Animal::$cat as non static 以非静态方式访问静态属性Animal::$cat
echo Animal::$cat."在吃饭".PHP_EOL; //取静态变量不能使用$this->cat了,而要使用双冒号 Animal::$cat 这样的方法来取. 这种方法使用类名取静态变量,但是一般也不用类名去取静态变量.而是用self去取.
echo self::$cat."在吃饭".PHP_EOL;//内部使用self来取
echo $this::$cat."在吃饭".PHP_EOL;//使用$this来取,也可以取到,但是不推荐,容易出错.
}
}
$cat = new Animal;
Animal::$cat = "小毛毛";//在外部对类的静态属性$cat进行操作,这里将$cat改成了"小毛毛".
$cat->name = "小花猫";
$cat->eat();
//所有对静态变量的操作都会对所有的对象起作用:意思是静态变量是根据对应的类来执行的,他跟类有关系,跟对象没有明确的关系.第21行对类内部的静态属性$cat进行修改后,所有的对象都产生了相应的变化.
$dog = new Animal;
Animal::$cat = "小咪咪";//这里同样在外部操作了类的静态属性,但由于执行顺序靠后,只对这行代码后的操作产生影响.
$dog->name = "小花猫";
$dog->eat();
类常量
<?php
//学会:如何定义常量,如何取到常量,如何输出常量.
//类常量:const MAOMAO = "小猫";
//使用场景:所有对象共用一个属性,当一个属性可以被多个对象共用,就可以把这个值定义为常量.
//静态属性与类常量相似,唯一的区别是类常量不可以更改,静态属性可以更改.
//静态变量即可以在类内部被调用,也可以在外部被调用.
class Animal{
public static $cat = "小猫-静态变量";
const MAOMAO = "小猫常量";
public function eat(){
echo self::MAOMAO;//内部调用.外部调用该方法即可取到变量.
}
}
new Animal;
echo (new Animal)->eat().PHP_EOL;
echo Animal::MAOMAO.PHP_EOL; //外部调用常量,这里写在了new前面,并且能正常执行,说明外部调用常量无序调用一个新对象.
$const = new Animal; //这里是new一个新对象,否则下一行调用方法无法执行.
echo $const->eat().PHP_EOL; //外部调用方法,方法内调用了常量.
//Animal::MAOMAO = "大猫";//这里尝试改变常量的值,可以发现常量一旦在类中被定义,在外部无法被改变.
echo $const::MAOMAO.PHP_EOL;
echo Animal::MAOMAO.PHP_EOL;
//静态变量即可以在类内部被调用,也可以在外部被调用.
echo Animal::MAOMAO; //外部调用常量,方法1.
$cat = new Animal; echo $cat::MAOMAO; //外部调用常量方法2.
echo Animal::$cat;//外部调用静态变量,方法1.
$cat1 =new Animal; echo $cat1::$cat; //外部调用静态变量方法2.
静态方法
<?php
//学习1如何在静态方法中调用非静态变量.(line:23)
// 2如何在静态方法中调用非静态方法.(line:24)
//静态方法,public static function 方法名()
//可以调用静态方法,静态变量
//可以调用非静态方法,非静态变量
class Animal{
public $name = "小猫";
public static $cat = "小猫眯";
const MAOMAO = "小毛毛常量";
public function eat(){
echo self::MAOMAO; //调用常量
echo self::$cat; //调用静态变量
echo $this->name; //调用非静态变量
}
//静态方法
public static function say(){
//echo self::$name;//这里使用静态方法调用非静态变量,$name既不是静态变量也不是常量,如果调用的话结果会报错.
echo self::$cat.PHP_EOL;//这里调用静态变量,正常执行.
echo self::MAOMAO.PHP_EOL; //这里调用常量,正常执行
//echo $this->name;//这里使用$this来调用非静态变量,但是报错,不能使用$this来调用静态方法.
echo (new self)->name.PHP_EOL;//这里使用new来定义一个新的对象,再来调用非静态变量.
echo (new self)->eat().'调用了静态方法eat'.PHP_EOL;//这里使用new来定义一个新对象,再来调用非静态方法.
}
}
(new Animal)::say(); //这里使用双冒号调用静态方法,正常执行
(new Animal)->say(); //这里使用箭头调用静态方法,正常执行
类的继承
<?php
//类的继承:extends , 指可以创建一个新的类,该类继承了(extends) 了父类的属性和方法,并且可以添加自己的属性和方法.通过继承,可以避免重复编写相似的代码,并且可以实现代码的重用.
//注意:继承不一定能重用.
//写法:如Cat类继承已存在的Animal类: class Cat extends Animal(){}.
//学习:子类继承父类后,能够继承父类那些东西,如何调用父类的属性或方法.包括受保护,私有的.
class Animal{
public $name = "小猫";
public $age = 3;
private $birth = '2024'; //私有,在外部以及父类子类都无权访问.
protected $id = "007"; //受保护,但可以被其自身以及其子类和父类访问
const ID = 001;
}
class Cat extends Animal{
public function getId(){
echo $this->id; //子类内部定义一个方法来获取受保护的属性.
}
}
var_dump(new Animal);
echo "<br>";
var_dump(new Cat); //通过查看结果对比两个对象出了名字不一样,其代码完全一模一样,说明Cat已经完全继承了父类的属性.
//验证Cat是否能使用父类的属性和方法.经过验证子类是完全可以使用父类的属性和方法的.
$cat = new Cat;//通过new把Cat类实例化成一个对象
echo $cat->name;
//echo $cat->id;//无法在外部去拿到protected的数据.需要从子类的内部去拿(line:13).
echo PHP_EOL ;$cat->getId(); //通过定义一个新的方法来获取受保护的属性,然后在外部调用该方法即可.
echo $cat->birth; //子类无法获取父类私有的属性或方法.
类的继承2
<?php
//学习:
//子类可以继承父类的属性和方法,子类如何调用父类的属性和方法
//父类无法使用子类的属性和方法
//父类受保护变量无法在外部修改或调用.报错
//复习了构造函数的用法,子类继承了父类的构造函数:在创建一个新对象时,他会被自动调用.他可以用来初始化对象的属性或者执行其他必要的操作.没有返回值.
class Animal{
protected $name = "小白";
public function __construct($name){
$this->name = $name;
}
public function eat(){
echo $this->name."在吃饭";
}
}
//子类
class Cat extends Animal{
public function meow(){
echo $this->name."在喵呜";
}
}
//子类继承父类后,可以在外部调用父类的属性和方法.
$cat = new Cat("小黑");//new一个新的对象,并赋值,这里属于子类的内部操作.因此可以赋值
// $cat->name = "小bai";//父类受保护变量无法在外部修改或调用.报错
var_dump($cat);
$cat->eat(); //这里继承了父类的方法
$cat->meow();//这里是子类Cat()自己的方法
子类的方法和属性的重写
<?php
//子类的方法和属性的重写:如果从父类继承的属性或方法不能满足子类需求,可以对其进行改写
//比如子类继承了父类的方法后,对某一方法可以进行改写,名字可以不变,这样可以覆盖掉父类的同名方法,执行时只执行子类的自己的同名方法.
//比如子类继承了父类的属性后,也可以在子类对该属性进行改写,只作用于自己,对父类不产生影响.
class Animal{
protected $name = "小狗狗";
public function __construct($name){
$this->name = "$name";
}
public function eat(){
echo $this->name.'在吃饭';
}
}
class Cat extends Animal{
protected $name = "小毛驴";
public function eat(){
echo $this->name.'大吃大喝';
}
public function meow(){
echo $this->name.'在喵呜';
}
}
$cat = new Cat("小黑");
var_dump($cat);
echo $cat->eat().PHP_EOL; //执行了Cat自己的eat()方法,而父类的同名方法被覆盖没有执行.
echo $cat->meow(); //Cat函数自己的方法.
echo PHP_EOL; //换行
//验证父类调用eat()方法
$animal = new Animal("animal");
echo $animal->eat();//执行了父类Animal自己的eat()方法,不受子类影响.
final
<?php
// 学习:为什么会需要用到final:因为有时候需要调用第三方的类,比如用include,require来引入,或使用composer安装第三方的库,而第三方还是担心你在使用他们的类库时,在继承他们的方法时使用了同名的方法,导致他们的方法被覆盖从而产生一系列的报错.使用final可以预防这些问题
// final:作用是防止类被继承 防止类的方法被重写不希望这个类被重写或继承导致代码报错.最主要的
//比如类不想被继承,在类的最前面加上final关键字
//比如类的方法不想被重新,在方法的最前面加上final关键字
//注意final不能用于属性.
final class Animal{ //加上final防止被继承
final public function eat(){
}
}
class Animal{
final public function eat(){ //加上final防止被重写,如果子类尝试重写会直接报错.
}
}
调用父类的方法
<?php
//调用父类的方法:
//parent::
//parent::__construct(){}
//学习:如何在类的内部调用父类的方法.比如在子类中调用say方法的时候,还去调用父类里面的eat方法.就可以在say方法里面使用parent::eat()来调用.
//学习:除了调用类似eat()这样的普通方法,还可以调用构造函数.调用了父类的构造函数后,父类的构造函数会被覆盖,如果不写$this->name = $name;的话,相当于$name未被赋值,输出结果没有名字.想要让$name赋值的第二种方法是直接调用父类的构造函数.
//学习:在构造函数传参的时候,除了$name还可以额外添加自己的属性,然后在输出的时候填写相应的参数.line20添加额外属性,line37添加对应额外参数.
class Animal{
public $name;
public function __construct($name){
$this->name = $name;
}
public function eat(){
echo $this->name."在吃饭";
}
}
class Cat extends Animal{
public function __construct($name,$age="8"){ //在构造函数传参的时候,除了$name还可以额外添加自己的属性,然后在输出的时候填写相应的参数.line20添加额外属性,line37添加对应额外参数.
// $this->name = $name; //如果不写$this->name = $name;的话,相当于$name未被赋值,输出结果没有名字.
parent::__construct($name); //也可以调用父类的构造函数来初始化属性参数.
echo "这是Cat自己的构造函数".$age.PHP_EOL;
}
public function eat(){
echo $this->name."在大吃大喝";
}
public function say(){
parent::eat();
echo $this->name."在说话";
}
}
$cat = new Cat("DAM",10);
echo $cat->say();
静态延迟绑定
<?php
//静态延迟绑定:static::$name --是指在运行时根据实际调用的类来确定静态方法或属性的绑定语法
class Animal{
protected static $name = "小动物";
public static function eat(){
echo self::$name."在吃饭";
echo "------";
echo self::$name."在吃饭";
echo "------";
echo static::$name."在吃饭".PHP_EOL;
}
}
class Cat extends Animal{
protected static $name = "小猫";
}
Animal::eat(); //调用静态方法使用双冒号
echo PHP_EOL;
Cat::eat(); //这里使用子类来调用eat()
类的多肽
<?php
//面向对象有三个特性:封装,继承和多肽
//多肽:
//多肽性允许不同类的对象对相同的消息做出不同的响应
//多态性通过方法重写(覆盖)和方法重载来实现
//方法重写是指子类重写父类的方法,以改变方法的实现细节
//方法重载是指在同一个类中根据参数个数或类型不同来实现不同功能
//方法重载函数:func_get_args()---获取参数; func_num_args()---获取参数的数量
//需要注意的是:多态性只适用于继承关系的类,子类必须重写父类的方法才能实现多态性
class Animal{
protected $name ="动物";
public function makeSound(){
echo $this->name."在吼叫";
}
}
class Dog extends Animal{
protected $name = "小狗";
public function makeSound(){
echo $this->name."在汪汪";
}
}
class Cat extends Animal{
protected $name= "小猫";
public function makeSound(){
echo $this->name."在喵呜";
}
}
// (new Animal)->makeSound().PHP_EOL;
$dog = new Animal;
$cat = new Animal;
echo (new Animal)->makeSound().PHP_EOL;
echo $dog->makeSound().PHP_EOL;
echo $cat->makeSound();
接口
<?php
//接口:interface 接口名{} ---接口是一组方法,不是类,不能被实例化.
//接口的作用:通常用于定义一些规范,让代码执行起来更加有条理,不易出错.
//给使用接口的人定义规范 ---可以指定某个类必须实现哪些方法,但不需要指定方法的具体内容
//接口定义方法只能使用public 可以定义公共方法和静态方法.
//接口可以定义常量,方法,静态方法等.
//使用接口的人必须按照规范来写,接口有什么方法就得有什么方法,具体怎么实现可以自己补充.
//使用接口的人不能修改接口的内容.比如常量,变量等.但是可以自己添加常量,变量.
interface Animal{
const MAOMAO = "小猫";
public function eat();
public function sleep();
public static function jump();
}
class Cat implements Animal{
public function eat(){
echo "eat";
}
public function sleep(){
echo "sleep";
}
public static function jump(){
echo "jump";
}
}
$cat = new Cat;
$cat->eat();echo PHP_EOL;
$cat->sleep();echo PHP_EOL;
$cat::jump();
trait 实现复用
trait 代码复用
解决类的单一继承问题
可同时使用多个trait,用逗号隔开
把常用的,同用户的代码抽离出来,写成trait
和类的继承非像,但是trait里面不能有类常量,且trait不能被实例化
根据下面类的继承来修改,对比下他们的相同点
trait Animal{
protected $name;
const MAOMAO = "catcat"; //类常量
public function __construct($name){
$this->name = $name;
} //trait中可以使用__construct构造函数
public function eat(){
echo $this->name."在吃饭";
}
}
class Cat {
use Animal; //使用trait
public function meow(){
echo $this->name." is miaowuing~";
}
}
$cat = new Cat("tom");
var_dump($cat);
$cat->eat(); //子类继承父类的方法eat
$cat->meow(); //子类自己的方法meow
trait 中可以使用抽象方法
<?php
trait Animal{
protected $name;
const MAOMAO = "catcat"; //类常量
abstract function test();
public function __construct($name){
$this->name = $name;
} //trait中可以使用__construct构造函数
public function eat(){
echo $this->name."在吃饭";
}
}
class Cat {
function test(){
echo "this is abstract method";
}
use Animal; //使用trait
public function meow(){
echo $this->name." is miaowuing~";
}
}
$cat = new Cat("tom");
var_dump($cat);
$cat->eat(); //子类继承父类的方法eat
$cat->meow(); //子类自己的方法meow
$cat->test(); //子类的抽象方法实现
trait 中可使用静态属性和静态方法
静态属性
在特质中定义静态属性时,可以使用 protected static $ count = 0; 这样的语法。 静态属性可以通过 self:: 来访问,确保访问到特质中定义的静态属性。
静态方法
特质中的静态方法可以通过 public static function incrementCount() { self:: $ count++; } 这样的语法来定义。 静态方法可以通过 MyClass::incrementCount(); 这样的方式来调用。
trait 中可使用其他trait
trait A{
public function Test(){
echo 'A里面的'.__METHOD__;
}
}
trait B{
use A;
public function TestB(){
echo 'B里面的'.__METHOD__;
}
}
class Tests{
use B;
}
$t = new Tests;
$t->Test();echo PHP_EOL;
$t->TestB();
trait 中可使用parent
//trait 中可以使用parent
class MainClass{
public function main(){
echo '这是主方法'.__METHOD__.PHP_EOL;
}
}
trait Animal{
public function eat(){
parent::main();
echo $this->name ." is eating";
echo PHP_EOL.__TRAIT__;
}
}
class Cat extends MainClass{
use Animal;
protected $name;
public function __construct($n){
$this->name = $n;
}
}
$cat = new Cat("Tom");
$cat->eat();
trait同名冲突
当一个类同时引入多个trait, 并且这些trait 中存在同名方法时,就会产生方法冲突.
instead of :替换同名方法, B::eat insteadof A;
, 将使用B的eat方法
as:重命名, A::eat as Aeat; ,$c->Aeat();, 将使用A的eat方法
使用as 还可以改变方法的权限, B::eat as protected Beat;
这将B的eat方法改名为Beat的同时修改了访问控制权限为protected.
使用as修改访问控制权限,protected 和 private 都可以.
as 和 insteadof 不能解决属性的冲突,比如trait A 和 trait B都有一个同名属性$name, 当他们的值不同的时候会出现报错,所以在定义多个 trait 的的时候,需要避免属性名重复防止冲突. 当不同 trait 的属性名和值都相同时则不会冲突.
<?php
trait A{
public function eat(){
echo 'eating a';
}
}
trait B{
public function eat(){
echo 'eating b';
}
}
class C{
use A,B{
// A::eat insteadof B;
B::eat insteadof A;
A::eat as Aeat;
}
}
$c = new C;
$c->eat();
$c->Aeat();
clone 和 __clone克隆对象