在面向对象中,我们很多程序员大多都习惯于使用动态方法,很少使用静态方法。而在学习其他人的框架中,我们却经常看到各种使用static修饰的方法。为什么会出现这种情况呢?
问原因也说不出来所以然,当然,我们或多或少也了解两者之间的一些区别与作用。比如,静态方法不需要new对象,通过类就可以使用。动态方法需要new了以后才可以使用。然后呢?我们还是习惯于用动态方法,不会去用静态方法。
什么时候该用动态方法,什么时候该用静态方法?
1.首先,动态方法和静态方法从形式来看区别在于有无static修饰:
public function fun(){}//动态方法
public static function fun(){}//静态方法
2.我们又了解到,static既可以用来定义静态方法,又可以用来定义静态属性。
而static修饰的静态方法只能访问静态属性。
无static修饰的动态方法既可以访问静态属性,又可以访问非静态属性。(看起来比静态方法更方便,难怪我们经常使用!)
3.但是呢?我们来看静态属性和非静态属性。
静态属性和非静态属性:
被static修饰的静态属性属于类,被所有对象所共用。存在静态存储区,也就是下图的数据区,整个程序运行都存在,占内存。
没被static修饰的非静态属性属于各个对象,各个对象都拥有一份拷贝。存在动态存储区,也就是下图的堆栈区,对象调用过后自动销毁。
4.我们总结,静态属性常驻内存,非静态属性不是,静态属性效率高,但占内存。
参照静态属性,联想到静态方法,于是我们又产生一个误解:
“ 静态方法常驻内存,动态方法不是,所以静态方法效率高但占内存。”?
事实上,函数本质上是可重用的代码片段。所以他们都是一样的,都在代码区,属于公用函数代码。在加载时机和占用内存上,静态方法和动态方法是一样的。都只存在一份代码,也就是只占用一份内存空间。
两者真正的区别仅仅在于:
静态方法只能访问静态属性。无this指针,不可以使用$this。使用访问符::访问方法。当然,也可以通过对象的->访问方法(兼容)。
动态方法隐含this指针,调用时需要实例化对象传递指针给方法。也就是要new一个对象出来,因为传递指针,比静态方法多一步,稍慢。使用访问符->访问方法。
5.静态与动态方法比较:
\ | 静态方法 | 动态方法 |
---|---|---|
static修饰 | 是 | 否 |
访问静态属性和方法 | 可以 | 可以 |
访问非静态属性和方法 | 不可以 | 可以 |
this变量指针 | 没有 | 有 |
归属 | 属于类,所有对象共用 | 属于各个对象,要传递自身指针 |
运行速度 | 不传递this指针,稍快 | 不传递this指针,稍快 |
访问符 | :: | -> |
存储区域 | 程序代码区 | 程序代码区 |
6.什么时候使用静态方法?
事实上如果一个方法与他所在类的实例对象无关,那么它就应该是静态的,而不应该把它写成动态方法。所以所有的动态方法都与对象有关,既然与对象有关,那么创建对象就是必然的步骤。
当然你完全可以把所有的对象方法都写成静态的,将对象作为参数传入即可,一般情况下可能不会出什么问题。
从面向对象的角度上来说,在抉择使用动态方法或静态方法时,应该根据是否该方法和实例化对象具有逻辑上的相关性,如果是就应该使用动态方法,反之使用静态方法。这只是从面向对象角度上来说的。
推荐:当方法内部没有访问到非静态的成员时(对象特有的数据),那么该方法可以定义成静态的。
例如以下代码:
class Person{
public static $country="中国";
public $name;
public $age;
public function say(){
echo $country." 你好!";
}
}
对象都有自己的属性。例如,每个人都有自己的名字和年龄,但是用户都是中国人。那么国籍就可以固定成静态值。
虽然这个say()方法是个动态方法,可以访问静态值,但可以加上static,表示跟对象无关,任何对象调用该方法都会获得同样的结果。这样更具有语义性。