先看需求
一群小孩在玩游戏,且不断有新玩家加入,用面向对象的思想统计有多少玩家?
方案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