php面向对象——静态属性和方法

先看需求

一群小孩在玩游戏,且不断有新玩家加入,用面向对象的思想统计有多少玩家?
方案1: 设置全局变量 用于统计

$num = 0;
class Child{
    public $name;
    public function __construct($name){
        $this->name = $name;
    }
    public function join(){
        echo $this->name,'加入游戏<br>';
        global $num;
        $num++;
    }
}

$p1 = new Child('孙悟空');
$p2 = new Child('白骨精');
$p1->join();
$p2->join();

echo '有',$num,'个玩家';

优化方案1:使用静态变量代替全局变量

静态变量属于所有对象,可以被所有对象共享

class Child{
    public static $num = 0;
    public $name;
    public function __construct($name){ 
        $this->name = $name;
    }
    public function join(){ 
        echo $this->name,'加入游戏<br>';
        // 在类中 访问本类的静态变量可以用self代替类名
        self::$num++; 
    }
}

$p1 = new Child('孙悟空');
$p2 = new Child('白骨精');
$p1->join();
$p2->join();

echo '有',Child::$num,'个玩家';

内存分析图
在这里插入图片描述

静态属性介绍

  • 静态属性是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个对象去修改它时,修改的也是同一个变量
  • 定义静态属性 static 修饰符 静态属性名
  • 静态属性不依赖于对象,new对象时,不复制到对象内存中,而是单独开内存,对象中的变量名指向它,必须静态访问

静态属性的访问

  • 在类外用 类名::静态属性名 访问,在类内可以用 self::静态属性名 访问,self代替类名
  • 静态属性的访问权限完全遵循权限修饰符的规则
  • ::叫做范围解析符,使用::访问叫做静态访问
  • 静态属性必须静态访问 类名::静态属性名

self和$this的区别

  • 使用方式不同 self:: $this->
  • self指向类,$this指向对象实例

静态属性练习题

请设计一个Person类, (有 名字, 年龄 和 蛋糕 三个属性)
1.蛋糕一共1000块,是所有人共享的.
2.创建唐僧师徒四人,他们每人都吃蛋糕, 唐僧每天吃 3块,悟空吃5块,沙3.和尚吃9块,猪八戒吃 30块. (编写一个 eat方法来吃)
4.请计算,蛋糕一共可以吃多少天.,还剩多少块蛋糕

class Person{
    public static $cake = 1000; // 设为静态属性
    public $name;
    public function __construct($name){
        $this->name = $name;
    }
    public function eat($num){
        if (self::$cake>=$num){
            self::$cake -= $num;
            return true;    // 重点在这里
        }else{
            echo '今天',$this->name,'吃不饱了,只剩下',self::$cake,'块<br>';
            return false;   // 重点在这里
        }

    }
    public function show(){
        return self::$cake;
    }
}

$p1 = new Person('唐僧');
$p2 = new Person('悟空');
$p3 = new Person('沙僧');
$p4 = new Person('八戒');

$day = 0;
while (1){
    if (! $p1->eat(3)){
        break;  // 重点看这里
    }
    if (! $p2->eat(5)) {
        break;
    }
    if (! $p3->eat(9)) {
        break;
    }
    if (! $p4->eat(30)) {
        break;
    }
    $day ++;
}

echo '总共吃了',$day,'天';

静态方法介绍

  • 静态方法是专门用来操作静态属性的
  • 定义静态方法, 普通方法前加 static关键字
  • 静态方法专门用于操作静态属性

静态方法的访问

  • 在类外用 类名::静态方法名() 访问,在类内可以用 self::静态方法名() 访问,self代替类名
  • 静态方法可以静态访问,也可以用对象访问 (语法支持 不推荐)
  • 静态方法的访问权限完全遵循权限修饰符的规则
  • 普通方法一般用对象访问,也可以静态访问 (注意$this绑定)
  • 静态访问不进行$this绑定

代码示例

class Person{
    private static $cake = 1000; // 设为静态属性

    // 静态方法操作静态属性
    public static function set_cake()
    {
        self::$cake = 500;
        echo Person::$cake;
    }
}

// 用静态方法操作静态属性 可以不依赖对象 直接用类名直接操作
Person::set_cake(); // 500

静态方法的访问细节

  • 在类外部调用静态方法,类名::静态方法名 或 对象名->静态方法名 或 对象名::静态方法(语法支持,但是不推荐)
  • 在类内部调用静态方法,self::静态方法名 或 对象名->静态方法名 用 $this也可以
  • 静态方法中只能访问静态属性,不能访问非静态属性
  • 普通方法中既能访问静态属性,也能访问非静态属性
  • 静态方法的访问权限完全遵循权限修饰符的规则
  • 静态访问不进行$this绑定

在类外部调用静态方法

class Person{
   private static $cake = 1000; // 设为静态属性

    // 静态方法操作静态属性
    public static function set_cake()
    {
        self::$cake -= 100;
        echo Person::$cake,'<br>';
    }
}

// 方式一  【推荐】
Person::set_cake(); // 900
// 下面两种【语法支持 不推荐】
$p1 = new Person();
$p1->set_cake();    // 800
$p1::set_cake();    // 700

在类内部调用静态方法

class Person{
    private static $cake = 1000; // 设为静态属性

    // 静态方法设为private无法在类外直接访问 静态方法操作静态属性
    private static function set_cake()
    {
        self::$cake -= 100;
        echo Person::$cake,'<br>';
    }
    // 在类内设置public方法,在类外间接访问
    public function test(){
        // 方式一  【推荐】
        self::set_cake();   // 900
        // 下面三种【不推荐】
        Person::set_cake(); // 800
        $this->set_cake();  // 700
        $this::set_cake();  // 600
    }
}

$p1 = new Person();
$p1->test();

静态调用不进行this绑定

  • 静态调用类中所有类型的方法都不需要绑定this
  • 静态方法中本身就不能有this,自然不存在绑定this
  • 对象调用类中的静态方法,不需要绑定this,因为,静态方法不属于哪个对象
  • 对象调用类中的非静态方法时,该方法执行之前先完成一个绑定, this绑定到调用此方法的对象
  • 静态调用非静态方法是不推荐的,但在继承中常用来访问父类方法,如parent::__construct()

测试示例

同一个类内

// 三个例子证明 `$b`绑定`bar()`的`this`后,`bar()`中的程序不管拐到哪里,`$this`的绑定都不会丢失
class B{
    public function foo(){
        if (isset($this)){
            echo 'this is defined~',get_class($this),"\n";
        }else{
            echo 'this is not defined',"\n";
        }
    }

    public function bar(){  
        B::foo();
    }
}

$b = new B();
$b->bar();  // bar()是非静态方法,$b绑定到$this, bar(){B::foo()-这里是静态调用,不操作$this},因此this is defined~B
B::bar();   // 静态调用 未绑定$this  this is not defined
B::foo();   // 静态调用 未绑定$this  this is not defined

不同类内

class A{
    public function foo(){
        if (isset($this)){
            echo 'this is defined~',get_class($this),"\n";
        }else{
            echo 'this is not defined',"\n";
        }
    }
}

class B{
    public function bar(){	// $b->bar()  $b绑定B类中的$this   并没有绑定A类中的$this
        A::foo();   // 静态调用不执行this绑定   用类名调用即静态调用
    }
}


$a = new A();
$a->foo();   // foo()是非静态方法,$a绑定到$this,因此 this is defined~A
A::foo();    // 静态调用 未绑定$this  this is not defined

$b = new B();
$b->bar();   // bar()是非静态方法,$b绑定到$this, bar(){B::foo()-这里是静态调用,不操作$this},因此this is defined~B
B::bar();    // 静态调用 未绑定$this  this is not defined

继承

class A{
    public function foo(){
        if (isset($this)){
            echo 'this is defined~',get_class($this),"\n";
        }else{
            echo 'this is not defined',"\n";
        }
    }

}


class B extends A{
    public function bar(){
        parent::foo();
    }
}

$b = new B();
$b->bar();  // bar()是非静态方法,$b绑定了bar()方法中的$this, bar(){parent::foo()-这里是静态调用,不操作$this},因此this is defined~B
B::bar();   // 静态调用 未绑定$this  this is not defined
B::foo();   // 静态调用 未绑定$this  this is not defined

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值