PHP静态成员变量和非静态成员变量详解


Posted in PHP onFebruary 14, 2017

数据成员可以分静态变量、非静态变量两种.

静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员存在于内存,所以非静态成员可以直接访问类中静态的成员.

非成静态员:所有没有加Static的成员都是非静态成员,当类被实例化之后,可以通过实例化的类名进行访问..非静态成员的生存期决定于该类的生存期..而静态成员则不存在生存期的概念,因为静态成员始终驻留在内容中..

一个类中也可以包含静态成员和非静态成员,类中也包括静态构造函数和非静态构造函数..
分两个方面来总结,第一方面主要是相对于面向过程而言,即在这方面不涉及到类,第二方面相对于面向对象而言,主要说明static在类中的作用。

一、在面向过程设计中的static关键字

1、静态全局变量

定义:在全局变量前,加上关键字 static 该变量就被定义成为了一个静态全局变量。

特点:

A、该变量在全局数据区分配内存。

B、初始化:如果不显式初始化,那么将被隐式初始化为0(自动变量是随机的,除非显式地初始化)。

C、访变量只在本源文件可见,严格的讲应该为定义之处开始到本文件结束。

例(摘于C++程序设计教程---钱能主编P103): //file1.cpp 
//Example 1
       #include 
       void fn();
        static int n; //定义静态全局变量
        void main()
        {
    n=20;
    cout<    fn();
        }
        void fn()
        {
    n++;
    cout<        }

D、文件作用域下声明的const的常量默认为static存储类型。

静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况如下图: 

PHP静态成员变量和非静态成员变量详解

一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。细心的读者可能会发现,Example 1中的代码中将

                 static int n; //定义静态全局变量

改为:

int n; //定义全局变量

程序照样正常运行。的确,定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:

  • 静态全局变量不能被其它文件所用;(好像是区别extern的)
  • 其它文件中可以定义相同名字的变量,不会发生冲突;

您可以将上述示例代码改为如下:

//Example 2
//File1
#include 
void fn();
static int n; //定义静态全局变量(只能在本文件中使用)
void main()
{
 n=20;
 cout<
extern int n;(可在别的文件中引用这个变量)
void fn()
{
 n++;
 cout<

编译并运行Example 2,您就会发现上述代码可以分别通过编译,但link时出现错误。试着将
static int n; //定义静态全局变量

改为

int n; //定义全局变量

再次编译运行程序,细心体会全局变量和静态全局变量的区别。

2、静态局部变量

定义:在局部变量前加上static关键字时,就定义了静态局部变量。

我们先举一个静态局部变量的例子,如下:

//Example 3
#include 
void fn();
void main()
{
 fn();
 fn();
 fn();
}
void fn()
{
 static n=10;
 cout<

通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。

但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。

静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。

特点:

A、该变量在全局数据区分配内存。

B、初始化:如果不显式初始化,那么将被隐式初始化为0,以后的函数调用不再进行初始化。

C、它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或 语句块结束时,其作用域随之结束。

3、静态函数(注意与类的静态成员函数区别)

定义:在函数的返回类型前加上static关键字,函数即被定义成静态函数。

特点:

A、静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

静态函数的例子:

//Example 4
#include 
static void fn();//声明静态函数
void main()
{
 fn();
}
void fn()//定义静态函数
{
 int n=10;
 cout<

定义静态函数的好处:

  • 静态函数不能被其它文件所用;
  • 其它文件中可以定义相同名字的函数,不会发生冲突;

二、面向对象的static关键字(类中的static关键字)

1、静态数据成员

在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员。先举一个静态数据成员的例子。

//Example 5
#include 
class Myclass
{
public:
 Myclass(int a,int b,int c);
 void GetSum();
private:
 int a,b,c;
 static int Sum;//声明静态数据成员
};
int Myclass::Sum=0;//定义并初始化静态数据成员
Myclass::Myclass(int a,int b,int c)
{
 this->a=a;
 this->b=b;
 this->c=c;
 Sum+=a+b+c;
}

void Myclass::GetSum()
{
 cout<<"Sum="<

可以看出,静态数据成员有以下特点:

  • 对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
  • 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;
  • 静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
  • 因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
  • 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
  • <数据类型><类名>::<静态数据成员名>=<值>
  • 类的静态数据成员有两种访问形式:
  • <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
  • 如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
  • 静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;
  • 同全局变量相比,使用静态数据成员有两个优势:

静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;

可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;

2、静态成员函数

与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。下面举个静态成员函数的例子。

//Example 6
#include 
class Myclass
{
public:
 Myclass(int a,int b,int c);
 static void GetSum();/声明静态成员函数
private:
 int a,b,c;
 static int Sum;//声明静态数据成员
};
int Myclass::Sum=0;//定义并初始化静态数据成员
Myclass::Myclass(int a,int b,int c)
{
 this->a=a;
 this->b=b;
 this->c=c;
 Sum+=a+b+c; //非静态成员函数可以访问静态数据成员
}
void Myclass::GetSum() //静态成员函数的实现
{
// cout<

类的静态成员与一般的类成员不同: 静态成员与对象的实例无关,只与类本身有关。他们用来实现类要封装的功能和数据,但不包括特定对象的功能和数据,静态成员包括静态方法和静态属性。

静态属性包含在类中要封装的数据,可以由所有类的实例共享。实际上,除了属于一个固定的类并限制访问方式外,类的静态属性非常类似于函数的全局变量。

静态方法则实现类需要封装的功能,与特定的对象无关. 静态方法非常类似于全局函数. 静态方法可以完全访问类的属性,也可以由对象的实例来访问,不论访问的限定语是否是什么。

不包含任何非静态成员的类可以称作静态类,一个静态类也可以理解为一个全局变量和函数的命名空间!

普通的方法用->来调用. PHP会建立一个this变量,静态方法不属于任何对象.在有些情况下,我们甚至希望在不存在有效的对象时调用它,那么就应该使用静态方法. PHP将不在静态方法内部建立this变量,即使你从一个对象中调用它们。

你可以写一个方法通过判断this是否建立来显示是否它被静态地或者非静态地调用. 当然,如果你用了static 关键字,不管它怎样被调用,这个方法总是静态的。

你的类也可以定义常量属性,不需要使用public static,只需要用const关键字即可. 常量属性总是静态的.它们是类的属性,而不是实例化该类的对象的属性。

PHP静态方法与非静态方法效率的问题

1、静态成员访问效率并不一定比非静态成员高;

2、只需要调用一个类的方法的返回值,使用静态方法更合理,否则会因为new而有额外的开销。

以上所述是小编给大家介绍的PHP静态成员变量和非静态成员变量,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

PHP 相关文章推荐
从零开始 教你如何搭建Discuz!4.1论坛
Jul 07 PHP
php 读取文件乱码问题
Feb 20 PHP
一个基于PDO的数据库操作类
Mar 24 PHP
第四章 php数学运算
Dec 30 PHP
php用正则表达式匹配URL的简单方法
Nov 12 PHP
ThinkPHP之A方法实例讲解
Jun 20 PHP
PHP常用的排序和查找算法
Aug 06 PHP
ZF框架实现发送邮件的方法
Dec 03 PHP
关于PHP 如何用 curl 读取 HTTP chunked 数据
Feb 26 PHP
Laravel使用Caching缓存数据减轻数据库查询压力的方法
Mar 15 PHP
PHP十六进制颜色随机生成器功能示例
Jul 24 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
Sep 28 PHP
PHP静态成员变量
Feb 14 #PHP
php中序列化与反序列化详解
Feb 13 #PHP
PHP最常用的正则表达式
Feb 13 #PHP
PHP面相对象中的重载与重写
Feb 13 #PHP
PHP中overload与override的区别
Feb 13 #PHP
PHP处理Ajax请求与Ajax跨域问题
Feb 13 #PHP
curl 出现错误的调试方法(必看)
Feb 13 #PHP
You might like
php+xml结合Ajax实现点赞功能完整实例
2015/01/30 PHP
浅谈php错误提示及查错方法
2015/07/14 PHP
php防止用户重复提交表单
2015/11/02 PHP
PHP遍历目录文件的常用方法小结
2017/02/03 PHP
php-fpm开启状态统计的方法详解
2017/06/23 PHP
PHP解决高并发的优化方案实例
2020/12/10 PHP
百度Popup.js弹出框进化版 拖拽小框架发布 兼容IE6/7/8,Firefox,Chrome
2010/04/13 Javascript
监控 url fragment变化的js代码
2010/04/19 Javascript
jQuery中append()方法用法实例
2014/12/25 Javascript
JavaScript中document对象使用详解
2015/01/06 Javascript
Bootstrap基础学习
2015/06/16 Javascript
JS触发服务器控件的单击事件(详解)
2016/08/06 Javascript
jsonp跨域请求实现示例
2017/03/13 Javascript
详解微信小程序 通过控制CSS实现view隐藏与显示
2017/05/24 Javascript
es6学习之解构时应该注意的点
2017/08/29 Javascript
Bootstrap4如何定制自己的颜色和风格
2018/02/26 Javascript
详解小程序开发经验:多页面数据同步
2019/05/18 Javascript
实用的Vue开发技巧
2019/05/30 Javascript
JS使用for in有序获取对象数据
2020/05/19 Javascript
使用scrapy实现爬网站例子和实现网络爬虫(蜘蛛)的步骤
2014/01/23 Python
linux下python抓屏实现方法
2015/05/22 Python
Python smallseg分词用法实例分析
2015/05/28 Python
使用FastCGI部署Python的Django应用的教程
2015/07/22 Python
详解python算法之冒泡排序
2019/03/05 Python
python 通过邮件控制实现远程控制电脑操作
2020/03/16 Python
python自动下载图片的方法示例
2020/03/25 Python
pycharm 使用tab跳出正在编辑的括号(){}{}等问题
2021/02/26 Python
ROSEFIELD手表荷兰官方网上商店:北欧极简设计女士腕表品牌
2018/01/24 全球购物
专注澳大利亚特产和新西兰特产的澳洲中文网:0061澳洲制造
2019/03/24 全球购物
一套中级Java程序员笔试题
2015/01/14 面试题
PHP引擎php.ini参数优化深入讲解
2021/03/24 PHP
环保倡议书100字
2014/05/15 职场文书
聘任通知书
2015/09/21 职场文书
SQLServer中JSON文档型数据的查询问题解决
2021/06/27 SQL Server
MySQL派生表联表查询实战过程
2022/03/20 MySQL
数据分析数据库ClickHouse在大数据领域应用实践
2022/04/03 MySQL