热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

php超全局变量,魔术常量,魔术方法

整理了下关于php的基础知识,参考了些资料,如下:超全局变量超全局变量—超全局变量是在全部作用域中始终可用的内置变量:$GL

整理了下关于php的基础知识,参考了些资料,如下:

超全局变量

超全局变量 — 超全局变量是在全部作用域中始终可用的内置变量:

$GLOBALS

$GLOBALS — 引用全局作用域中可用的全部变量

  • 说明

一个包含了全部变量的全局组合数组。变量的名字就是数组的键。

  • 范例

function test() {$foo = "local variable";echo '$foo in global scope: ' . $GLOBALS["foo"] . "\n";echo '$foo in current scope: ' . $foo . "\n";
}$foo = "Example content";
test();
?>

以上例程的输出类似于:

$foo in global scope: Example content
$foo in current scope: local variable

$_SERVER

$_SERVER -- $HTTP_SERVER_VARS [已删除] — 服务器和执行环境信息

  • 说明

$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。不能保证每个服务器都提供全部项目;服务器可能会忽略一些,或者提供一些没有在这里列举出来的项目。这也就意味着大量的此类变量都会在» CGI 1.1 规范中说明,所以应该仔细研究一下。

Note: PHP 5.4.0 之前,$HTTP_SERVER_VARS 包含着相同的信息,但它不是一个超全局变量。 (注意
$HTTP_SERVER_VARS 与 $_SERVER 是不同的变量,PHP处理它们的方式不同)
  • 目录

在 $_SERVER 中,你也许能够,也许不能够找到下面的这些元素。注意,如果以命令行方式运行 PHP,下面列出的元素几乎没有有效的(或是没有任何实际意义的)。

'PHP_SELF'
当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/foo/bar.php 的脚本中使用 $_SERVER['PHP_SELF'] 将得到 /foo/bar.php。__FILE__ 常量包含当前(例如包含)文件的完整路径和文件名。 从 PHP 4.3.0 版本开始,如果 PHP 以命令行模式运行,这个变量将包含脚本名。之前的版本该变量不可用。
'argv'
传递给该脚本的参数的数组。当脚本以命令行方式运行时,argv 变量传递给程序 C 语言样式的命令行参数。当通过 GET 方式调用时,该变量包含query string。
'argc'
包含命令行模式下传递给该脚本的参数的数目(如果运行在命令行模式下)。
'GATEWAY_INTERFACE'
服务器使用的 CGI 规范的版本;例如,“CGI/1.1”。
'SERVER_ADDR'
当前运行脚本所在的服务器的 IP 地址。
'SERVER_NAME'
当前运行脚本所在的服务器的主机名。如果脚本运行于虚拟主机中,该名称是由那个虚拟主机所设置的值决定。
Note: 在 Apache 2 里,必须设置 UseCanonicalName = On 和 ServerName。 否则该值会由客户端提供,就有可能被伪造。 上下文有安全性要求的环境里,不应该依赖此值。
'SERVER_SOFTWARE'
服务器标识字符串,在响应请求时的头信息中给出。
'SERVER_PROTOCOL'
请求页面时通信协议的名称和版本。例如,“HTTP/1.0”。
'REQUEST_METHOD'
访问页面使用的请求方法;例如,“GET”, “HEAD”,“POST”,“PUT”。
Note:如果请求方法为 HEAD,PHP 脚本将在发送 Header 头信息之后终止(这意味着在产生任何输出后,不再有输出缓冲)。
'REQUEST_TIME'
请求开始时的时间戳。从 PHP 5.1.0 起可用。
'REQUEST_TIME_FLOAT'
请求开始时的时间戳,微秒级别的精准度。 自 PHP 5.4.0 开始生效。
'QUERY_STRING'
query string(查询字符串),如果有的话,通过它进行页面访问。
'DOCUMENT_ROOT'
当前运行脚本所在的文档根目录。在服务器配置文件中定义。
'HTTP_ACCEPT'
当前请求头中 Accept: 项的内容,如果存在的话。
'HTTP_ACCEPT_CHARSET'
当前请求头中 Accept-Charset: 项的内容,如果存在的话。例如:“iso-8859-1,*,utf-8”。
'HTTP_ACCEPT_ENCODING'
当前请求头中 Accept-Encoding: 项的内容,如果存在的话。例如:“gzip”。
'HTTP_ACCEPT_LANGUAGE'
当前请求头中 Accept-Language: 项的内容,如果存在的话。例如:“en”。
'HTTP_CONNECTION'
当前请求头中 Connection: 项的内容,如果存在的话。例如:“Keep-Alive”。
'HTTP_HOST'
当前请求头中 Host: 项的内容,如果存在的话。
'HTTP_REFERER'
引导用户代理到当前页的前一页的地址(如果存在)。由 user agent 设置决定。并不是所有的用户代理都会设置该项,有的还提供了修改 HTTP_REFERER 的功能。简言之,该值并不可信。
'HTTP_USER_AGENT'
当前请求头中 User-Agent: 项的内容,如果存在的话。该字符串表明了访问该页面的用户代理的信息。一个典型的例子是:Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586)。除此之外,你可以通过 get_browser() 来使用该值,从而定制页面输出以便适应用户代理的性能。
'HTTPS'
如果脚本是通过 HTTPS 协议被访问,则被设为一个非空的值。
Note: 注意当使用 IIS 上的 ISAPI 方式时,如果不是通过 HTTPS 协议被访问,这个值将为 off。
'REMOTE_ADDR'
浏览当前页面的用户的 IP 地址。
'REMOTE_HOST'
浏览当前页面的用户的主机名。DNS 反向解析不依赖于用户的 REMOTE_ADDR。
Note: 你的服务器必须被配置以便产生这个变量。例如在 Apache 中,你需要在 httpd.conf 中设置 HostnameLookups On 来产生它。参见 gethostbyaddr()。
'REMOTE_PORT'
用户机器上连接到 Web 服务器所使用的端口号。
'REMOTE_USER'
经验证的用户
'REDIRECT_REMOTE_USER'
验证的用户,如果请求已在内部重定向。
'SCRIPT_FILENAME'
当前执行脚本的绝对路径。
Note:如果在命令行界面(Command Line Interface, CLI)使用相对路径执行脚本,例如 file.php 或 ../file.php,那么 $_SERVER['SCRIPT_FILENAME'] 将包含用户指定的相对路径。
'SERVER_ADMIN'
该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上,则该值是那个虚拟主机的值。
'SERVER_PORT'
Web 服务器使用的端口。默认值为 “80”。如果使用 SSL 安全连接,则这个值为用户设置的 HTTP 端口。
Note: 在 Apache 2 里,为了获取真实物理端口,必须设置 UseCanonicalName = On 以及 UseCanonicalPhysicalPort = On。 否则此值可能被伪造,不一定会返回真实端口值。 上下文有安全性要求的环境里,不应该依赖此值。
'SERVER_SIGNATURE'
包含了服务器版本和虚拟主机名的字符串。
'PATH_TRANSLATED'
当前脚本所在文件系统(非文档根目录)的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。
Note: 自 PHP 4.3.2 起,PATH_TRANSLATED 在 Apache 2 SAPI 模式下不再和 Apache 1 一样隐含赋值,而是若 Apache 不生成此值,PHP 便自己生成并将其值放入 SCRIPT_FILENAME 服务器常量中。这个修改遵守了 CGI 规范,PATH_TRANSLATED 仅在 PATH_INFO 被定义的条件下才存在。 Apache 2 用户可以在 httpd.conf 中设置 AcceptPathInfo = On 来定义 PATH_INFO。
'SCRIPT_NAME'
包含当前脚本的路径。这在页面需要指向自己时非常有用。__FILE__ 常量包含当前脚本(例如包含文件)的完整路径和文件名。
'REQUEST_URI'
URI 用来指定要访问的页面。例如 “/index.html”。
'PHP_AUTH_DIGEST'
当作为 Apache 模块运行时,进行 HTTP Digest 认证的过程中,此变量被设置成客户端发送的“Authorization” HTTP 头内容(以便作进一步的认证操作)。
'PHP_AUTH_USER'
当 PHP 运行在 Apache 或 IIS(PHP 5 是 ISAPI)模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的用户名。
'PHP_AUTH_PW'
当 PHP 运行在 Apache 或 IIS(PHP 5 是 ISAPI)模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的密码。
'AUTH_TYPE'
当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是认证的类型。
'PATH_INFO'
包含由客户端提供的、跟在真实脚本名称之后并且在查询语句(query string)之前的路径信息,如果存在的话。例如,如果当前脚本是通过 URL http://www.example.com/php/pa... 被访问,那么 $_SERVER['PATH_INFO'] 将包含 /some/stuff。
'ORIG_PATH_INFO'
在被 PHP 处理之前,“PATH_INFO” 的原始版本。

  • 范例

echo $_SERVER['SERVER_NAME'];
?>

以上例程的输出类似于:

www.example.com

$_GET

$_GET — HTTP GET 变量

  • 说明

通过 URL 参数传递给当前脚本的变量的数组。

  • 范例

echo 'Hello ' . htmlspecialchars($_GET["name"]) . '!';
?>

假设用户访问的是 http://example.com/?name=Hannes

以上例程的输出类似于:

Hello Hannes!

$_POST

$_POST — HTTP POST 变量

  • 说明

当 HTTP POST 请求的 Content-Type 是 application/x-www-form-urlencoded 或 multipart/form-data 时,会将变量以关联数组形式传入当前脚本。

$HTTP_POST_VARS 包含相同的信息,但它不是一个超全局变量。 (注意 $HTTP_POST_VARS 和 $_POST 是不同的变量,PHP 处理它们的方式不同)

  • 范例

echo 'Hello ' . htmlspecialchars($_POST["name"]) . '!';
?>

假设用户通过 HTTP POST 方式传递了参数 name=Hannes

以上例程的输出类似于:

Hello Hannes!

$_FILES

$_FILES — HTTP 文件上传变量

  • 说明

通过 HTTP POST 方式上传到当前脚本的项目的数组。 此数组的概况在 POST 方法上传 章节中有描述。

$HTTP_POST_FILES 包含相同的信息,但它不是一个超全局变量。 (注意 $HTTP_POST_FILES 和 $_FILES 是不同的变量,PHP 处理它们的方式不同)

$_REQUEST

$_REQUEST — HTTP Request 变量

  • 说明

默认情况下包含了 $_GET,$_POST 和 $_COOKIE 的数组。

$_SESSION

$_SESSION — Session 变量

  • 说明

当前脚本可用 SESSION 变量的数组。更多关于如何使用的信息,参见 Session 函数 文档。

$HTTP_SESSION_VARS 包含相同的信息,但它不是一个超全局变量。 (注意 $HTTP_SESSION_VARS 和 $_SESSION 是不同的变量,PHP 处理它们的方式不同)

$_ENV

$_ENV -- $HTTP_ENV_VARS [已弃用] — 环境变量

  • 说明

通过环境方式传递给当前脚本的变量的数组。

这些变量被从 PHP 解析器的运行环境导入到 PHP 的全局命名空间。很多是由支持 PHP 运行的 Shell 提供的,并且不同的系统很可能运行着不同种类的 Shell,所以不可能有一份确定的列表。请查看你的 Shell 文档来获取定义的环境变量列表。

其他环境变量包含了 CGI 变量,而不管 PHP 是以服务器模块还是 CGI 处理器的方式运行。

$HTTP_ENV_VARS 包含相同的信息,但它不是一个超全局变量。 (注意 $HTTP_ENV_VARS 和 $_ENV 是不同的变量,PHP 处理它们的方式不同)

  • 范例

echo 'My username is ' .$_ENV["USER"] . '!';
?>

假设 "bjori" 运行此段脚本

以上例程的输出类似于:

My username is bjori!

$_COOKIE

$_COOKIE -- $HTTP_COOKIE_VARS [已弃用] — HTTP COOKIEs

  • 说明

通过 HTTP COOKIEs 方式传递给当前脚本的变量的数组。

$HTTP_COOKIE_VARS 包含相同的信息,但它不是一个超全局变量。 (注意 $HTTP_COOKIE_VARS 和 $_COOKIE 是不同的变量,PHP 处理它们的方式不同)

  • 范例

echo 'Hello ' . htmlspecialchars($_COOKIE["name"]) . '!';
?>

假设之前发送了 "name" COOKIE

以上例程的输出类似于:

Hello Hannes!

魔术常量

PHP 向它运行的任何脚本提供了大量的预定义常量。不过很多常量都是由不同的扩展库定义的,只有在加载了这些扩展库时才会出现,或者动态加载后,或者在编译时已经包括进去了。

有八个魔术常量它们的值随着它们在代码中的位置改变而改变。例如 __LINE__ 的值就依赖于它在脚本中所处的行来决定。这些特殊的常量不区分大小写,如下:

几个 PHP 的“魔术常量”


名称说明
__LINE__文件中的当前行号。
__FILE__文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。自 PHP 4.0.2 起,__FILE__总是包含一个绝对路径(如果是符号连接,则是解析后的绝对路径),而在此之前的版本有时会包含一个相对路径。
__DIR__文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。它等价于 dirname(__FILE__)。除非是根目录,否则目录中名不包括末尾的斜杠。(PHP 5.3.0中新增)
__FUNCTION__函数名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。
__CLASS__类的名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。类名包括其被声明的作用区域(例如 FooBar)。注意自 PHP 5.4 起 __CLASS__ 对 trait 也起作用。当用在 trait 方法中时,__CLASS__ 是调用 trait 方法的类的名字。
__TRAIT__Trait 的名字(PHP 5.4.0 新加)。自 PHP 5.4 起此常量返回 trait 被定义时的名字(区分大小写)。Trait 名包括其被声明的作用区域(例如 FooBar)。
__METHOD__类的方法名(PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。
__NAMESPACE__当前命名空间的名称(区分大小写)。此常量是在编译时定义的(PHP 5.3.0 新增)。
参见 get_class(),get_object_vars(),file_exists() 和 function_exists()。

魔术方法

以下内容转自脚本之家PHP之十六个魔术方法详细介绍,如有侵权,联系删除。
PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用。 魔术方法包括:

方法名说明
__construct()类的构造函数
__destruct()类的析构函数
__call()在对象中调用一个不可访问方法时调用
__callStatic()用静态方式中调用一个不可访问方法时调用
__get()获得一个类的成员变量时调用
__set()设置一个类的成员变量时调用
__isset()当对不可访问属性调用isset()或empty()时调用
__unset()当对不可访问属性调用unset()时被调用。
__sleep()执行serialize()时,先会调用这个函数
__wakeup()执行unserialize()时,先会调用这个函数
__toString()类被当成字符串时的回应方法
__invoke()调用函数的方式调用一个对象时的回应方法
__set_state()调用var_export()导出类时,此静态方法会被调用。
__clone()当对象复制完成时调用
__autoload()尝试加载未定义的类
__debugInfo()打印所需调试信息

下面让我们以实例的形式向大家讲解下这几个魔术方法时如何使用的。

一、 __construct(),类的构造函数

php中构造方法是对象创建完成后第一个被对象自动调用的方法。在每个类中都有一个构造方法,如果没有显示地声明它,那么类中都会默认存在一个没有参数且内容为空的构造方法。

1、 构造方法的作用

通常构造方法被用来执行一些有用的初始化任务,如对成员属性在创建对象时赋予初始值。

2、 构造方法的在类中的声明格式

function __constrct([参数列表]){方法体 //通常用来对成员属性进行初始化赋值
}

3、 在类中声明构造方法需要注意的事项

1、在同一个类中只能声明一个构造方法,原因是,PHP不支持构造函数重载

2、构造方法名称是以两个下画线开始的__construct()
下面是它的例子:

name = $name;$this->sex = $sex;$this->age = $age;}/*** say 方法*/public function say(){ echo "我叫:" . $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age;} }创建对象$Person1且不带任参数$Person1 = new Person();
echo $Person1->say(); //输出:我叫:,性别:男,年龄:27
创建对象$Person2且带参数“小明”$Person2 = new Person("小明");
echo $Person2->say(); //输出:我叫:张三,性别:男,年龄:27
创建对象$Person3且带三个参数$Person3 = new Person("李四","男",25);
echo $Person3->say(); //输出:我叫:李四,性别:男,年龄:25

二、__destruct(),类的析构函数

通过上面的讲解,现在我们已经知道了什么叫构造方法。那么与构造方法对应的就是析构方法。

析构方法允许在销毁一个类之前执行的一些操作或完成一些功能,比如说关闭文件、释放结果集等。

析构方法是PHP5才引进的新内容。

析造方法的声明格式与构造方法 __construct() 比较类似,也是以两个下划线开始的方法 __destruct() ,这种析构方法名称也是固定的。

1、 析构方法的声明格式

function __destruct()
{//方法体
}

注意:析构函数不能带有任何参数。

2、 析构方法的作用

一般来说,析构方法在PHP中并不是很常用,它属类中可选择的一部分,通常用来完成一些在对象销毁前的清理任务
举例演示,如下:

class Person{ public $name; public $age; public $sex; public function __construct($name="", $sex="男", $age=22){ $this->name = $name;$this->sex = $sex;$this->age = $age;}/*** say 说话方法*/public function say(){ echo "我叫:".$this->name.",性别:".$this->sex.",年龄:".$this->age;} /*** 声明一个析构方法*/public function __destruct(){echo "我觉得我还可以再抢救一下,我的名字叫".$this->name;}
}$Person = new Person("小明");
unset($Person); //销毁上面创建的对象$Person

上面的程序运行时输出:

我觉得我还可以再抢救一下,我的名字叫小明

三、 __call(),在对象中调用一个不可访问方法时调用。

该方法有两个参数,第一个参数 $function_name 会自动接收不存在的方法名,第二个 $arguments 则以数组的方式接收不存在方法的多个参数。

1、 __call() 方法的格式:

function __call(string $function_name, array $arguments)
{// 方法体
}

2、 __call() 方法的作用:

为了避免当调用的方法不存在时产生错误,而意外的导致程序中止,可以使用 __call() 方法来避免。

该方法在调用的方法不存在时会自动调用,程序仍会继续执行下去。
请参考如下代码:

class Person
{ function say(){ echo "Hello, world!
"; } /*** 声明此方法用来处理调用对象中不存在的方法*/function __call($funName, $arguments){ echo "你所调用的函数:" . $funName . "(参数:" ; // 输出调用不存在的方法名print_r($arguments); // 输出调用不存在的方法时的参数列表echo ")不存在!
\n"; // 结束换行 }
}
$Person = new Person();
$Person->run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法
$Person->eat("小明", "苹果");
$Person->say();

运行结果:

你所调用的函数:run(参数:Array ( [0] => teacher ) )不存在!你所调用的函数:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在!Hello, world!

四、 __callStatic(),用静态方式中调用一个不可访问方法时调用

此方法与上面所说的 __call() 功能除了 __callStatic() 是为静态方法准备的之外,其它都是一样的。

请看下面代码:

class Person
{function say(){echo "Hello, world!
";}/*** 声明此方法用来处理调用对象中不存在的方法*/public static function __callStatic($funName, $arguments){echo "你所调用的静态方法:" . $funName . "(参数:" ; // 输出调用不存在的方法名print_r($arguments); // 输出调用不存在的方法时的参数列表echo ")不存在!
\n"; // 结束换行}
}
$Person = new Person();
$Person::run("teacher"); // 调用对象中不存在的方法,则自动调用了对象中的__call()方法
$Person::eat("小明", "苹果");
$Person->say();

运行结果如下:

你所调用的静态方法:run(参数:Array ( [0] => teacher ) )不存在!
你所调用的静态方法:eat(参数:Array ( [0] => 小明 [1] => 苹果 ) )不存在!
Hello, world!

五、 __get(),获得一个类的成员变量时调用

在 php 面向对象编程中,类的成员属性被设定为 private 后,如果我们试图在外面调用它则会出现“不能访问某个私有属性”的错误。那么为了解决这个问题,我们可以使用魔术方法 __get()。

魔术方法__get()的作用
在程序运行过程中,通过它可以在对象的外部获取私有成员属性的值。
我们通过下面的 __get() 的实例来更进一步的连接它吧:

class Person
{private $name;private $age;function __construct($name="", $age=1){$this->name = $name;$this->age = $age;}/*** 在类中添加__get()方法,在直接获取属性值时自动调用一次,以属性名作为参数传入并处理* @param $propertyName** @return int*/public function __get($propertyName){ if ($propertyName == "age") {if ($this->age > 30) {return $this->age - 10;} else {return $this->$propertyName;}} else {return $this->$propertyName;}}
}
$Person = new Person("小明", 60); // 通过Person类实例化的对象,并通过构造方法为属性赋初值
echo "姓名:" . $Person->name . "
"; // 直接访问私有属性name,自动调用了__get()方法可以间接获取
echo "年龄:" . $Person->age . "
"; // 自动调用了__get()方法,根据对象本身的情况会返回不同的值

运行结果:

姓名:小明
年龄:50

六、 __set(),设置一个类的成员变量时调用

__set() 的作用:
__set( $property, $value )` 方法用来设置私有属性, 给一个未定义的属性赋值时,此方法会被触发,传递的参数是被设置的属性名和值。

请看下面的演示代码:

class Person
{private $name;private $age;public function __construct($name&#61;"", $age&#61;25){$this->name &#61; $name;$this->age &#61; $age;}/*** 声明魔术方法需要两个参数&#xff0c;真接为私有属性赋值时自动调用&#xff0c;并可以屏蔽一些非法赋值* &#64;param $property* &#64;param $value*/public function __set($property, $value) {if ($property&#61;&#61;"age"){if ($value > 150 || $value <0) {return;}}$this->$property &#61; $value;}/*** 在类中声明说话的方法&#xff0c;将所有的私有属性说出*/public function say(){echo "我叫".$this->name."&#xff0c;今年".$this->age."岁了";}
}$Person&#61;new Person("小明", 25); //注意&#xff0c;初始值将被下面所改变
//自动调用了__set()函数&#xff0c;将属性名name传给第一个参数&#xff0c;将属性值”李四”传给第二个参数
$Person->name &#61; "小红"; //赋值成功。如果没有__set()&#xff0c;则出错。
//自动调用了__set()函数&#xff0c;将属性名age传给第一个参数&#xff0c;将属性值26传给第二个参数
$Person->age &#61; 16; //赋值成功
$Person->age &#61; 160; //160是一个非法值&#xff0c;赋值失效
$Person->say(); //输出&#xff1a;我叫小红&#xff0c;今年16岁了

运行结果&#xff1a;

我叫小红&#xff0c;今年16岁了

七、 __isset()&#xff0c;当对不可访问属性调用isset()或empty()时调用

在看这个方法之前我们看一下isset()函数的应用&#xff0c;isset()是测定变量是否设定用的函数&#xff0c;传入一个变量作为参数&#xff0c;如果传入的变量存在则传回true&#xff0c;否则传回false。

那么如果在一个对象外面使用isset()这个函数去测定对象里面的成员是否被设定可不可以用它呢&#xff1f;

分两种情况&#xff0c;如果对象里面成员是公有的&#xff0c;我们就可以使用这个函数来测定成员属性&#xff0c;如果是私有的成员属性&#xff0c;这个函数就不起作用了&#xff0c;原因就是因为私有的被封装了&#xff0c;在外部不可见。那么我们就不可以在对象的外部使用isset()函数来测定私有成员属性是否被设定了呢&#xff1f;当然是可以的&#xff0c;但不是一成不变。你只要在类里面加上一个__isset()方法就可以了&#xff0c;当在类外部使用isset()函数来测定对象里面的私有成员是否被设定时&#xff0c;就会自动调用类里面的__isset()方法了帮我们完成这样的操作。

__isset()的作用&#xff1a;当对不可访问属性调用 isset() 或 empty() 时&#xff0c;__isset() 会被调用
请看下面代码演示&#xff1a;

class Person
{public $sex;private $name;private $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}/*** &#64;param $content** &#64;return bool*/public function __isset($content) {echo "当在类外部使用isset()函数测定私有成员{$content}时&#xff0c;自动调用
";echo isset($this->$content);}
}$person &#61; new Person("小明", 25); // 初始赋值
echo isset($person->sex),"
";
echo isset($person->name),"
";
echo isset($person->age),"
";

运行结果如下&#xff1a;

1 // public 可以 isset()
当在类外部使用isset()函数测定私有成员name时&#xff0c;自动调用 // __isset() 内 第一个echo
1 // __isset() 内第二个echo
当在类外部使用isset()函数测定私有成员age时&#xff0c;自动调用 // __isset() 内 第一个echo
1 // __isset() 内第二个echo

八、 __unset()&#xff0c;当对不可访问属性调用unset()时被调用。

看这个方法之前呢&#xff0c;我们也先来看一下 unset() 函数&#xff0c;unset()这个函数的作用是删除指定的变量且传回true&#xff0c;参数为要删除的变量。

那么如果在一个对象外部去删除对象内部的成员属性用unset()函数可以吗&#xff1f;

这里自然也是分两种情况&#xff1a;

1、 如果一个对象里面的成员属性是公有的&#xff0c;就可以使用这个函数在对象外面删除对象的公有属性。

2、 如果对象的成员属性是私有的&#xff0c;我使用这个函数就没有权限去删除。

虽然有以上两种情况&#xff0c;但我想说的是同样如果你在一个对象里面加上__unset()这个方法&#xff0c;就可以在对象的外部去删除对象的私有成员属性了。在对象里面加上了__unset()这个方法之后&#xff0c;在对象外部使用“unset()”函数删除对象内部的私有成员属性时&#xff0c;对象会自动调用__unset()函数来帮我们删除对象内部的私有成员属性。

请看如下代码&#xff1a;

class Person
{public $sex;private $name;private $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}/*** &#64;param $content** &#64;return bool*/public function __unset($content) {echo "当在类外部使用unset()函数来删除私有成员时自动调用的
";echo isset($this->$content);}
}$person &#61; new Person("小明", 25); // 初始赋值
unset($person->sex);
unset($person->name);
unset($person->age);

运行结果&#xff1a;

当在类外部使用unset()函数来删除私有成员时自动调用的
1当在类外部使用unset()函数来删除私有成员时自动调用的

九、 __sleep()&#xff0c;执行serialize()时&#xff0c;先会调用这个函数

serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在&#xff0c;则该方法会优先被调用&#xff0c;然后才执行序列化操作。

此功能可以用于清理对象&#xff0c;并返回一个包含对象中所有应被序列化的变量名称的数组。

如果该方法未返回任何内容&#xff0c;则 NULL 被序列化&#xff0c;并产生一个 E_NOTICE 级别的错误。

注意&#xff1a;

__sleep() 不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。
作用&#xff1a;

__sleep() 方法常用于提交未提交的数据&#xff0c;或类似的清理操作。同时&#xff0c;如果有一些很大的对象&#xff0c;但不需要全部保存&#xff0c;这个功能就很好用。
具体请参考如下代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}/*** &#64;return array*/public function __sleep() {echo "当在类外部使用serialize()时会调用这里的__sleep()方法
";$this->name &#61; base64_encode($this->name);return array(&#39;name&#39;, &#39;age&#39;); // 这里必须返回一个数值&#xff0c;里边的元素表示返回的属性名称}
}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
echo serialize($person);
echo &#39;
&#39;;

代码运行结果&#xff1a;

当在类外部使用serialize()时会调用这里的__sleep()方法
O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}

十、 __wakeup()&#xff0c;执行unserialize()时&#xff0c;先会调用这个函数

如果说 __sleep() 是白的&#xff0c;那么 __wakeup() 就是黑的了。

那么为什么呢&#xff1f;

因为&#xff1a;

与之相反&#xff0c;unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在&#xff0c;则会先调用 __wakeup 方法&#xff0c;预先准备对象需要的资源。
作用&#xff1a;
__wakeup() 经常用在反序列化操作中&#xff0c;例如重新建立数据库连接&#xff0c;或执行其它初始化操作。
还是看代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}/*** &#64;return array*/public function __sleep() {echo "当在类外部使用serialize()时会调用这里的__sleep()方法
";$this->name &#61; base64_encode($this->name);return array(&#39;name&#39;, &#39;age&#39;); // 这里必须返回一个数值&#xff0c;里边的元素表示返回的属性名称}/*** __wakeup*/public function __wakeup() {echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法
";$this->name &#61; 2;$this->sex &#61; &#39;男&#39;;// 这里不需要返回数组}
}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
var_dump(serialize($person));
var_dump(unserialize(serialize($person)));

运行结果&#xff1a;

当在类外部使用serialize()时会调用这里的__sleep()方法
string(58) "O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}" 当在类外部使用serialize()时会调用这里的__sleep()方法
当在类外部使用unserialize()时会调用这里的__wakeup()方法
object(Person)#2 (3) { ["sex"]&#61;> string(3) "男" ["name"]&#61;> int(2) ["age"]&#61;> int(25) }

十一、 __toString()&#xff0c;类被当成字符串时的回应方法

作用&#xff1a;

__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。
注意&#xff1a;

此方法必须返回一个字符串&#xff0c;否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。
警告&#xff1a;

不能在 __toString() 方法中抛出异常。这么做会导致致命错误。
代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}public function __toString(){return &#39;go go go&#39;;}
}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
echo $person;

结果&#xff1a;

go go go

那么如果类中没有 __toString() 这个魔术方法运行会发生什么呢&#xff1f;让我们来测试下&#xff1a;

代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
echo $person;

结果&#xff1a;

Catchable fatal error: Object of class Person could not be converted to string in D:\phpStudy\WWW\test\index.php on line 18
很明显&#xff0c;页面报了一个致命错误&#xff0c;这是语法所不允许的。

十二、 __invoke()&#xff0c;调用函数的方式调用一个对象时的回应方法

作用&#xff1a;

尝试以调用函数的方式调用一个对象时&#xff0c;__invoke() 方法会被自动调用。
注意&#xff1a;

本特性只在 PHP 5.3.0 及以上版本有效。
直接上代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}public function __invoke() {echo &#39;这可是一个对象哦&#39;;}}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
$person();

查看运行结果&#xff1a;

这可是一个对象哦

当然&#xff0c;如果你执意要将对象当函数方法使用&#xff0c;那么会得到下面结果&#xff1a;

Fatal error: Function name must be a string in D:\phpStudy\WWW\test\index.php on line 18

十三、 __set_state()&#xff0c;调用var_export()导出类时&#xff0c;此静态方法会被调用。

作用&#xff1a;

自 PHP 5.1.0 起&#xff0c;当调用 var_export() 导出类时&#xff0c;此静态方法会被自动调用。
参数&#xff1a;

本方法的唯一参数是一个数组&#xff0c;其中包含按 array(&#39;property&#39; &#61;> value, ...) 格式排列的类属性。
下面我们先来看看在没有加 __set_state() 情况按下&#xff0c;代码及运行结果如何&#xff1a;

上代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
var_export($person);

看结果&#xff1a;

Person::__set_state(array( &#39;sex&#39; &#61;> &#39;男&#39;, &#39;name&#39; &#61;> &#39;小明&#39;, &#39;age&#39; &#61;> 25, ))

很明显&#xff0c;将对象中的属性都打印出来了

加了 __set_state() 之后&#xff1a;

继续上代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}public static function __set_state($an_array){$a &#61; new Person();$a->name &#61; $an_array[&#39;name&#39;];return $a;}}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
$person->name &#61; &#39;小红&#39;;
var_export($person);

继续看结果&#xff1a;

Person::__set_state(array( &#39;sex&#39; &#61;> &#39;男&#39;, &#39;name&#39; &#61;> &#39;小红&#39;, &#39;age&#39; &#61;> 25, ))

十四、 __clone()&#xff0c;当对象复制完成时调用

在多数情况下&#xff0c;我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要&#xff1a;如果你有一个 GTK 窗口对象&#xff0c;该对象持有窗口相关的资源。你可能会想复制一个新的窗口&#xff0c;保持所有属性与原来的窗口相同&#xff0c;但必须是一个新的对象&#xff08;因为如果不是新的对象&#xff0c;那么一个窗口中的改变就会影响到另一个窗口&#xff09;。还有一种情况&#xff1a;如果对象 A 中保存着对象 B 的引用&#xff0c;当你复制对象 A 时&#xff0c;你想其中使用的对象不再是对象 B 而是 B 的一个副本&#xff0c;那么你必须得到对象 A 的一个副本。

作用&#xff1a;

对象复制可以通过 clone 关键字来完成&#xff08;如果可能&#xff0c;这将调用对象的 __clone() 方法&#xff09;。对象中的 __clone() 方法不能被直接调用。

语法&#xff1a;

$copy_of_object &#61; clone $object;

注意&#xff1a;

当对象被复制后&#xff0c;PHP 5 会对对象的所有属性执行一个浅复制&#xff08;shallow copy&#xff09;。所有的引用属性 仍然会是一个指向原来的变量的引用。

当复制完成时&#xff0c;如果定义了 __clone() 方法&#xff0c;则新创建的对象&#xff08;复制生成的对象&#xff09;中的 __clone() 方法会被调用&#xff0c;可用于修改属性的值&#xff08;如果有必要的话&#xff09;。
看代码&#xff1a;

class Person
{public $sex;public $name;public $age;public function __construct($name&#61;"", $age&#61;25, $sex&#61;&#39;男&#39;){$this->name &#61; $name;$this->age &#61; $age;$this->sex &#61; $sex;}public function __clone(){echo __METHOD__."你正在克隆对象
";}}$person &#61; new Person(&#39;小明&#39;); // 初始赋值
$person2 &#61; clone $person;var_dump(&#39;persion1:&#39;);
var_dump($person);
echo &#39;
&#39;;
var_dump(&#39;persion2:&#39;);
var_dump($person2);

看结果&#xff1a;

Person::__clone你正在克隆对象
string(9) "persion1:" object(Person)#1 (3) { ["sex"]&#61;> string(3) "男" ["name"]&#61;> string(6) "小明" ["age"]&#61;> int(25) }
string(9) "persion2:" object(Person)#2 (3) { ["sex"]&#61;> string(3) "男" ["name"]&#61;> string(6) "小明" ["age"]&#61;> int(25) }

克隆成功。

十五、__autoload()&#xff0c;尝试加载未定义的类

作用&#xff1a;

你可以通过定义这个函数来启用类的自动加载
在魔术函数 __autoload() 方法出现以前&#xff0c;如果你要在一个程序文件中实例化100个对象&#xff0c;那么你必须用include或者require包含进来100个类文件&#xff0c;或者你把这100个类定义在同一个类文件中 —— 相信这个文件一定会非常大&#xff0c;然后你就痛苦了。

但是有了 __autoload() 方法&#xff0c;以后就不必为此大伤脑筋了&#xff0c;这个类会在你实例化对象之前自动加载制定的文件。

还是通过例子来看看吧&#xff1a;

先看看以往的方式&#xff1a;

/** * 文件non_autoload.php */ require_once(&#39;project/class/A.php&#39;);
require_once(&#39;project/class/B.php&#39;);
require_once(&#39;project/class/C.php&#39;); if (条件A) { $a &#61; new A(); $b &#61; new B(); $c &#61; new C(); // … 业务逻辑
} else if (条件B) { $a &#61; newA(); $b &#61; new B(); // … 业务逻辑
}

看到了吗&#xff1f;不用100个&#xff0c;只是3个看起来就有点烦了。而且这样就会有一个问题&#xff1a;如果脚本执行“条件B”这个分支时&#xff0c;C.php这个文件其实没有必要包含。因为&#xff0c;任何一个被包含的文件&#xff0c;无论是否使用&#xff0c;均会被php引擎编译。如果不使用&#xff0c;却被编译&#xff0c;这样可以被视作一种资源浪费。更进一步&#xff0c;如果C.php包含了D.php&#xff0c;D.php包含了E.php。并且大部分情况都执行“条件B”分支&#xff0c;那么就会浪费一部分资源去编译C.php,D.php,E.php三个“无用”的文件。

那么如果使用 __autoload() 方式呢&#xff1f;

/** * 文件autoload_demo.php */
function __autoload($className) { $filePath &#61; “project/class/{$className}.php”; if (is_readable($filePath)) { require($filePath); }
} if (条件A) { $a &#61; new A(); $b &#61; new B(); $c &#61; new C(); // … 业务逻辑
} else if (条件B) { $a &#61; newA(); $b &#61; new B(); // … 业务逻辑
}

ok,不论效率怎么用&#xff0c;最起码界面看起来舒服多了&#xff0c;没有太多冗余的代。

再来看看这里的效率如何&#xff0c;我们分析下&#xff1a;

当php引擎第一次使用类A&#xff0c;但是找不到时&#xff0c;会自动调用 __autoload 方法&#xff0c;并将类名“A”作为参数传入。所以&#xff0c;我们在 __autoload() 中需要的做的就是根据类名&#xff0c;找到相应的文件&#xff0c;并包含进来&#xff0c;如果我们的方法也找不到&#xff0c;那么php引擎就会报错了。

注意&#xff1a;

这里可以只用require&#xff0c;因为一旦包含进来后&#xff0c;php引擎再遇到类A时&#xff0c;将不会调用__autoload&#xff0c;而是直接使用内存中的类A&#xff0c;不会导致多次包含。
扩展&#xff1a;

其实php发展到今天&#xff0c;已经有将 spl_autoload_register — 注册给定的函数作为 __autoload 的实现了&#xff0c;但是这个不在啊本文讲解之内&#xff0c;有兴趣可以自行看手册。

十六、__debugInfo()&#xff0c;打印所需调试信息

注意&#xff1a;

该方法在PHP 5.6.0及其以上版本才可以用&#xff0c;如果你发现使用无效或者报错&#xff0c;请查看啊你的版本。
看代码&#xff1a;

class C {private $prop;public function __construct($val) {$this->prop &#61; $val;}/*** &#64;return array*/public function __debugInfo() {return [&#39;propSquared&#39; &#61;> $this->prop ** 2,];}
}var_dump(new C(42));

结果&#xff1a;

object(C)#1 (1) { ["propSquared"]&#61;> int(1764) }

再次注意&#xff1a;

这里的 ** 是乘方的意思&#xff0c;也是在PHP5.6.0及其以上才可以使用&#xff0c;详情请查看PHP手册



推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
author-avatar
谁许我一世繁华似锦
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有