一直依赖对于php中static关键字比较模糊,只是在单例模式中用过几回。上网查了查,没有找到很全的介绍,本身总结一下。php
根据使用位置分为两部分 一、函数体中的静态变量 二、类中的静态属性和方法html
1 函数体中的静态变量java
static $a = 1; function num1(){ static $a = 0; return $a++; } function num2(){ $a = 5555; global $a; echo $a++; } function num3(){ static $a = 100; return $a++; } echo num1(); //0 num2(); //1 echo $a; //2 echo num3(); //100 echo num3(); //101 echo num3(); //102
从中咱们看出几点c++
1 函数体中的静态变量与全局中的静态变量不冲突,只有在关键字global做用下才会使局部与全局统一编程
2 函数体中的静态变量在函数调用的时候只会被初始化一次c#
由于静态变量在全局数据区分配内存;此处要提一下 缓存在逻辑上大体区分为 栈 堆 全局区 程序代码区 文字常量区缓存
栈 存放变量名(会有一部分的整型,浮点型,字符串存放在此处)安全
堆 存放变量值函数
全局区 存放静态变量,全局变量post
程序代码区 存放要执行的函数及方法
文字常量区 存放常量等
大体是上面的样子,至关至关不严格,可是能够很好的帮助咱们记忆数据间的关系。
2 类中的静态成员
类中的静态成员包含静态属性和静态方法
class first{ public $num = 1;
//声明一个静态属性 static $name = '456'; //声明一个静态方法 public static function self_use(){ echo self::$name;
echo self::out(); } public static function static_use(){ echo static::out(); } public static function method(){ echo 'first'; } //这是一个错误的调用 public function my_wrong(){ //echo self::dis(); } public function dis(){ echo '只是作一个展现'; } } class second extends first { public static function method(){ echo 'second'; } } $one = new first(); $one::$name; $one->self_use();
$one->static_use();
$two = new second();
$two->self_use();
$two->static_use();
关于类中的静态方法咱们从两个角度介绍 1 使用角度 2 理论角度
1 在实际使用中咱们须要注意几点
a. 静态方法能够调用静态属性,禁止调用非静态属性。
b. 静态方法内不容许出现$this,出现就停掉脚本。
c. 在静态方法中调用类中其余静态方法有两种格式 self:: 和 static 。根据输出结果咱们了解到两种方式的区别是 使用 self::method() 调用本方法所在类的 method() 方法。使用static::method(),会调用整个继承家族最后定义的方法。
这个感受很绕绕啊,形象点理解就是在父类中声明一个静态方法A,子类中重写了这个静态方法A。在父类其余方法中使用self调用A,会执行父类中A的方法;可是使用static调用,就会执行子类A的方法;
2 从理论角度介绍
早期的结构化编程几乎都是静态方法,出现面向对象以后,才有了实例化方法的感念。而面向对象并不能彻底解决掉静态方法使用的问题。咱们能够这样理解,静态方法和实例化方法虽然都是类的,可是两者的调用方式是不一样的,静态方法和属性在类在使用class::就会被存进内存,而后使用。可是实例化方法和非静态属性,须要实例化 new以后才会被存进内存使用。这就解释了a 中静态方法不能调用非静态属性,你静态方法喊一嗓子就出来了,我非静态属性不行啊,没批准(new)我出不来啊;而b中的$this是面向对象出来以后的产物专门用于实例化对象时候调用对象中的属性和方法用的,是对象的专属技能,这个技能静态方法不能使用。
总结此处为看了以后总结的,我木有那么高水平:
你们对这个问题都有一个共识:那就是实例化方法更多被使用和稳妥,静态方法少使用。有时候咱们对静态方法和实例化方法会有一些误解。
一、你们都觉得“ 静态方法常驻内存,实例方法不是,因此静态方法效率高但占内存。”
事实上,他们都是同样的,在加载时机和占用内存上,静态方法和实例方法是同样的,在类型第一次被使用时加载。调用的速度基本上没有差异。
二、你们都觉得“ 静态方法在堆上分配内存,实例方法在堆栈上”
事实上全部的方法都不可能在堆或者堆栈上分配内存,方法做为代码是被加载到特殊的代码内存区域,这个内存区域是不可写的。
方法占不占用更多内存,和它是否是static没什么关系。
由于字段是用来存储每一个实例对象的信息的,因此字段会占有内存,而且由于每一个实例对象的状态都不一致(至少不能认为它们是一致的),因此每一个实例对象的全部字段都会在内存中有一分拷贝,也由于这样你才能用它们来区分你如今操做的是哪一个对象。
但方法不同,不论有多少个实例对象,它的方法的代码都是同样的,因此只要有一份代码就够了。所以不管是static仍是non-static的方法,都只存在一份代码,也就是只占用一分内存空间。
一样的代码,为何运行起来表现却不同?这就依赖于方法所用的数据了。主要有两种数据来源,一种就是经过方法的参数传进来,另外一种就是使用class的成员变量的值……
三、你们都觉得“实例方法须要先建立实例才能够调用,比较麻烦,静态方法不用,比较简单”
事实上若是一个方法与他所在类的实例对象无关,那么它就应该是静态的,而不该该把它写成实例方法。因此全部的实例方法都与实例有关,既然与实例有关,那么建立实例就是必然的步骤,没有麻烦简单一说。
固然你彻底能够把全部的实例方法都写成静态的,将实例做为参数传入便可,通常状况下可能不会出什么问题。
从面向对象的角度上来讲,在抉择使用实例化方法或静态方法时,应该根据是否该方法和实例化对象具备逻辑上的相关性,若是是就应该使用实例化对象 反之使用静态方法。这只是从面向对象角度上来讲的。
若是从线程安全、性能、兼容性上来看 也是选用实例化方法为宜。
咱们为何要把方法区分为:静态方法和实例化方法 ?
若是咱们继续深刻研究的话,就要脱离技术谈理论了。早期的结构化编程,几乎全部的方法都是“静态方法”,引入实例化方法概念是面向对象概念出现之后的事情了,区分静态方法和实例化方法不能单单从性能上去理解,建立c++,java,c#这样面向对象语言的大师引入实例化方法必定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化方式的区分是为了解决模式的问题。
拿别人一个例子说事:
好比说“人”这个类,每一个人都有姓名、年龄、性别、身高等,这些属性就应该是非静态的,由于每一个人都的这些属性都不相同;但人在生物学上属于哪一个门哪一个纲哪一个目等,这个属性是属于整我的类,因此就应该是静态的——它不依赖与某个特定的人,不会有某我的是“脊椎动物门哺乳动物纲灵长目”而某我的倒是“偶蹄目”的。
参考文献: