整理了下关于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手册