0

0

PHP面向对象中的重要知识点(三)

php中文网

php中文网

发布时间:2016-06-21 08:48:42

|

961人浏览过

|

来源于php中文网

原创

1. namespace:

 

    和C++中的名字空间很像,作用也一样,都是为了避免在引用较多第三方库时而带来的名字冲突问题。通过名字空间,即便两个class的名称相同,但是因为位于不同的名字空间内,他们仍然可以被精确定位和区分。第一次看到PHP的名字空间语法时,感觉和C++相比在语法上是非常非常相似的,然而在写点儿小例子做做实验的时候才发现,他们的差别还是很大的,为了避免以后忘记,所以这里特别将其记录了下来。见如下代码:

 

复制代码

php

立即学习PHP免费学习笔记(深入)”;

//in Test2.php

namespace nstest\test2;

 

class Test2 {

    public static function printMe() {

        print 'This is nstest\test2\Test2::printSelf.'."\n";

    }

}

 

//in Test1.php

namespace nstest\test1;

 

class Test1 {

    public static function printMe() {

        print 'This is nstest\test1\Test1::printSelf.'."\n";

    }

}

require "Test2.php";

nstest\test2\Test2::printMe();

复制代码

    运行结果如下:

 

bogon:TestPhp$ php Test1.php 

PHP Fatal error:  Class 'nstest\test1\nstest\test2\Test2' not found in /Users/liulei/PhpstormProjects/TestPhp/Test1.php on line 13

    是不是这个结果比较出乎意料,原因在哪呢?HOHO,原来PHP在进行名字空间引用的时候,如果名字空间的第一个字符不是前导斜杠(\),那么就被自动识别为相对名字空间,在上面的代码中,Test1自身所在的名字空间是namespace nstest\test1,因此在以nstest\test2\Test2::printMe()方式调用Test2::printMe()时,PHP将自动解析为nstest\test1\nstest\test2\Test2::printMe(),即认为nstest\test2是在当前名字空间内部的。修正该问题非常简单,只需在引用时加上前导斜杠(\)即可,见以下修复后的代码:     

 

复制代码

//Test2.php

namespace nstest\test2;

 

class Test2 {

    public static function printMe() {

        print 'This is nstest\test2\Test2::printSelf.'."\n";

    }

}

 

//Test1.php

namespace nstest\test1;

 

class Test1 {

    public static function printMe() {

        print 'This is nstest\test1\Test1::printSelf.'."\n";

    }

}

require "Test2.php";

\nstest\test2\Test2::printMe();

复制代码

    运行结果如下:

 

bogon:TestPhp$ php Test1.php 

This is nstest\test2\Test2::printSelf.

    还有一种改动方式,可以示意一下PHP中名字空间中的相对引用。这里我们可以将Test1的名字空间改为namespace nstest,其他的修改见以下代码中红色高亮部分:

 

复制代码

//Test2.php

namespace nstest\test2;

 

class Test2 {

    public static function printMe() {

        print 'This is nstest\test2\Test2::printSelf.'."\n";

    }

}

 

//Test1.php

namespace nstest;

 

class Test1 {

    public static function printMe() {

        print 'This is nstest\test1\Test1::printSelf.'."\n";

    }

}

 

require "Test2.php";

test2\Test2::printMe(); 

复制代码

    运行结果等于上面正确的结果。最重要的差别就是该例使用了PHP名字空间中的相对定位。相信熟悉C++的开发者一定会想到use关键字,PHP也提供了该关键字,他们的功能是一致的,都是为了避免在后面的代码中,无需再通过全限定符(类名前加名字空间前缀)来引用其他名字空间中的类了。至于具体的语法规则,还是看看下面具体的代码和关键性注释吧。

 

复制代码

//Test2.php

namespace nstest\test2;

 

class Test2 {

    public static function printMe() {

        print 'This is nstest\test2\Test2::printSelf.'."\n";

    }

}

 

//Test1.php

namespace nstest\test1;

 

class Test1 {

    public static function printMe() {

        print 'This is nstest\test1\Test1::printSelf.'."\n";

    }

}

 

require "Test2.php";

//这里需要特别注意的是,nstest\test2已经表示名字空间绝对路径定位,不需要再加前导斜杠(\)了。

//另外这里还有一个隐式规则是test2表示该名字空间的缺省别名,在引用其名字空间内的对象时需要加test2前缀。

use nstest\test2;

test2\Test2::printMe();

 

//这里我们也可以给名字空间显式的指定别名,如:

use nstest\test2 as test2_alias;

test2_alias\Test2::printMe(); 

复制代码

    运行结果如下:

 

bogon:TestPhp$ php Test1.php 

This is nstest\test2\Test2::printSelf.

This is nstest\test2\Test2::printSelf.

    最后介绍一下PHP中全局名字空间的引用方式,见如下代码和关键性注释:

 

复制代码

class Test {

    public static function printMe() {

        print 'This is Global namespace Test::printSelf.'."\n";

    }

}

 

//下面两行代码表示的是同一对象,即全局名字空间下的Test类,然而如果因为名字空间冲突导致第一种方式不能被PHP

//编译器正常识别,那么就可以使用第二种方式显式的通知PHP,自己要引用的是全局名字空间中的Test类。

Test::printMe();

\Test::printMe();

复制代码

    运行结果如下:

 

bogon:TestPhp$ php Test1.php 

This is Global namespace Test::printSelf.

This is Global namespace Test::printSelf.

2. Reflection:

 

    PHP中的反射和Java中java.lang.reflect包提供的功能一样,更有意思的是,就连很多方法命名和调用方式也是非常雷同的。他们都是由一些列可以分析类、类方法和方法参数的PHP内置类组成。我们这里主要介绍的是如下几个常用的内置类:(Reflection、RelectionClass、ReflectionMethod、ReflectionParameter和ReflectionProperty)。现在我们还是一步一步来理解,即从ReflectionClass开始给出示例代码和关键性注释: 

 

复制代码

class TestClass {

千博企业网站管理系统标准版2013 Build0206
千博企业网站管理系统标准版2013 Build0206

系统简介 千博企业建站系统是根据企业客户实际应用需求而提供的一套完整的中小企业网站应用解决方案,协助企业对公司产品进行更深层次的展示、推广。 千博企业建站系统主要面向企业进行产品展示、推广、企业形象展示而设计研发,系统界面简洁大方,管理操作非常简易,可高效构建企业、行业、律师、医院、政府信息门户网站、内部知识网站、信息门户等平台,并内置了专业的内容管理功能模块,可为浏览网站的顾客提供全方位的导购服

下载

    public $publicVariable;

 

    function publicMethod() {

        print "This is publicMethod.\n";

    }

}

 

function classInfo(ReflectionClass $c) {

    $details = "";

    //getName将返回实际的类名。

    $name = $c->getName();

    if ($c->isUserDefined()) {

        $details .= "$name is user defined.\n";

    }

    if ($c->isInternal()) {

        $details .= "$name is built-in.\n";

    }

    if ($c->isAbstract()) {

        $details .= "$name is abstract class.\n";

    }

    if ($c->isFinal()) {

        $details .= "$name is final class.\n";

    }

    if ($c->isInstantiable()) {

        $details .= "$name can be instantiated.\n";

    } else {

        $details .= "$name cannot be instantiated.\n";

    }

    return $details;

}

 

function classSource(ReflectionClass $c) {

    $path = $c->getFileName();

    $lines = @file($path);

    //获取类定义代码的起始行和截至行。

    $from = $c->getStartLine();

    $to = $c->getEndLine();

    $len = $to - $from + 1;

    return implode(array_slice($lines,$from - 1,$len));

}

 

print "The following is Class Information.\n";

print classInfo(new ReflectionClass('TestClass'));

 

print "\nThe following is Class Source.\n";

print classSource(new ReflectionClass('TestClass'));

复制代码

    运行结果如下:

 

复制代码

bogon:TestPhp$ php reflection_test.php 

The following is Class Information.

TestClass is user defined.

TestClass can be instantiated.

 

The following is Class Source.

class TestClass {

    public $publicVariable;

 

    function publicMethod() {

        print "This is publicMethod.\n";

    }

}

复制代码

    下面让我们仍然以代码示例和关键性注释的方法继续ReflectionMethod的学习之旅。

 

复制代码

class TestClass {

    public $publicVariable;

 

    function __construct() {

 

    }

    private function privateMethod() {

 

    }

    function publicMethod() {

        print "This is publicMethod.\n";

    }

    function publicMethod2(string $arg1, int $arg2) {

 

    }

}

 

//这个函数中使用的ReflectionMethod中的方法都是非常简单直观的,就不再过多赘述了。

function methodInfo(ReflectionMethod $m) {

    $name = $m->getName();

    $details = "";

    if ($m->isUserDefined()) {

        $details .= "$name is user defined.\n";

    }

    if ($m->isInternal()) {

        $details .= "$name is built-in.\n";

    }

    if ($m->isAbstract()) {

        $details .= "$name is abstract.\n";

    }

    if ($m->isPublic()) {

        $details .= "$name is public.\n";

    }

    if ($m->isProtected()) {

        $details .= "$name is protected.\n";

    }

    if ($m->isPrivate()) {

        $details .= "$name is private.\n";

    }

    if ($m->isStatic()) {

        $details .= "$name is static.\n";

    }

    if ($m->isFinal()) {

        $details .= "$name is final.\n";

    }

    if ($m->isConstructor()) {

        $details .= "$name is constructor.\n";

    }

    if ($m->returnsReference()) {

        $details .= "$name returns a reference.\n";

    }

    return $details;

}

 

function methodSource(ReflectionMethod $m) {

    $path = $m->getFileName();

    $lines = @file($path);

    $from = $m->getStartLine();

    $to = $m->getEndLine();

    $len = $to - $from + 1;

    return implode(array_slice($lines, $from - 1, $len));

}

 

$rc = new ReflectionClass('TestClass');

$methods = $rc->getMethods();

print "The following is method information.\n";

foreach ($methods as $method) {

    print methodInfo($method);

    print "\n--------------------\n";

}

 

print "The following is Method[TestClass::publicMethod] source.\n";

print methodSource($rc->getMethod('publicMethod'));

复制代码

    运行结果如下:

 

复制代码

bogon:TestPhp$ php reflection_test.php 

The following is method information.

__construct is user defined.

__construct is public.

__construct is constructor.

 

--------------------

privateMethod is user defined.

privateMethod is private.

 

--------------------

publicMethod is user defined.

publicMethod is public.

 

--------------------

publicMethod2 is user defined.

publicMethod2 is public.

 

--------------------

The following is Method[TestClass::publicMethod] source.

    function publicMethod() {

        print "This is publicMethod.\n";

    }

复制代码

    让我们继续ReflectionParameter吧,他表示的是成员函数的参数信息。继续看代码吧。

 

复制代码

class ParamClass {

 

}

 

class TestClass {

    function publicMethod() {

        print "This is publicMethod.\n";

    }

    function publicMethod2(ParamClass $arg1, &$arg2, $arg3 = null) {

 

    }

}

 

function paramInfo(ReflectionParameter $p) {

    $details = "";

    //这里的$declaringClass将等于TestClass。

    $declaringClass = $p->getDeclaringClass();

    $name = $p->getName();

    $class = $p->getClass();

    $position = $p->getPosition();

    $details .= "\$$name has position $position.\n";

    if (!empty($class)) {

        $classname = $class->getName();

        $details .= "\$$name must be a $classname object\n";

    }

    if ($p->isPassedByReference()) {

        $details .= "\$$name is passed by reference.\n";

    }

    if ($p->isDefaultValueAvailable()) {

        $def = $p->getDefaultValue();

        $details .= "\$$name has default: $def\n";

    }

    return $details;

}

 

$rc = new ReflectionClass('TestClass');

$method = $rc->getMethod('publicMethod2');

$params = $method->getParameters();

 

foreach ($params as $p) {

    print paramInfo($p)."\n";

}

复制代码

    运行结果如下:

 

复制代码

bogon:TestPhp$ php reflection_test.php 

$arg1 has position 0.

$arg1 must be a ParamClass object

 

$arg2 has position 1.

$arg2 is passed by reference.

 

$arg3 has position 2.

$arg3 has default: 

复制代码

    上面介绍的都是通过PHP提供的Reflection API来遍历任意class的具体信息,事实上和Java等其他语言提供的反射功能一样,PHP也同样支持通过反射类调用实际对象的方法,这里将主要应用到两个方法,分别是ReflectionClass::newInstance()来创建对象实例,另一个是ReflectionMethod::invoke(),根据对象实例和方法名执行该方法。见如下代码:

 

复制代码

class TestClass {

    private $privateArg;

    function __construct($arg) {

        $this->privateArg = $arg;

    }

    function publicMethod() {

        print '$privateArg = '.$this->privateArg."\n";

    }

 

    function publicMethod2($arg1, $arg2) {

        print '$arg1 = '.$arg1.' $arg2 = '.$arg2."\n";

    }

}

 

$rc = new ReflectionClass('TestClass');

$testObj = $rc->newInstanceArgs(array('This is private argument.'));

$method = $rc->getMethod('publicMethod');

$method->invoke($testObj);

 

$method2 = $rc->getMethod('publicMethod2');

$method2->invoke($testObj,"hello","world");

复制代码

    运行结果如下:

 

bogon:TestPhp$ php reflection_test.php 

$privateArg = This is private argument.

$arg1 = hello $arg2 = world

    事实上ReflectionClass、ReflectionMethod和ReflectionParameter提供给我们的可用方法还有更多,这里只是给出几个最典型的方法,以便我们可以更为直观的学习和了解PHP Reflection API。相信再看完以后的代码示例之后,我们都会比较清楚,如果今后需要用到和class相关的功能,就从ReflectionClass中查找,而member function的信息则一定来自于ReflectionMethod,方法参数信息来自于ReflectionParameter。

 

注:该Blog中记录的知识点,是在我学习PHP的过程中,遇到的一些PHP和其他面向对象语言相比比较独特的地方,或者是对我本人而言确实需要簿记下来以备后查的知识点。虽然谈不上什么深度,但是还是希望能与大家分享。



PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
2026春节习俗大全
2026春节习俗大全

本专题整合了2026春节习俗大全,阅读专题下面的文章了解更多详细内容。

68

2026.02.11

Yandex网页版官方入口使用指南_国际版与俄罗斯版访问方法解析
Yandex网页版官方入口使用指南_国际版与俄罗斯版访问方法解析

本专题全面整理了Yandex搜索引擎的官方入口信息,涵盖国际版与俄罗斯版官网访问方式、网页版直达入口及免登录使用说明,帮助用户快速、安全地进入Yandex官网,高效使用其搜索与相关服务。

200

2026.02.11

虫虫漫画网页版入口与免费阅读指南_正版漫画全集在线查看方法
虫虫漫画网页版入口与免费阅读指南_正版漫画全集在线查看方法

本专题系统整理了虫虫漫画官网及网页版最新入口,涵盖免登录观看、正版漫画全集在线阅读方式,并汇总稳定可用的访问渠道,帮助用户快速找到虫虫漫画官方页面,轻松在线阅读各类热门漫画内容。

40

2026.02.11

Docker容器化部署与DevOps实践
Docker容器化部署与DevOps实践

本专题面向后端与运维开发者,系统讲解 Docker 容器化技术在实际项目中的应用。内容涵盖 Docker 镜像构建、容器运行机制、Docker Compose 多服务编排,以及在 DevOps 流程中的持续集成与持续部署实践。通过真实场景演示,帮助开发者实现应用的快速部署、环境一致性与运维自动化。

4

2026.02.11

Rust异步编程与Tokio运行时实战
Rust异步编程与Tokio运行时实战

本专题聚焦 Rust 语言的异步编程模型,深入讲解 async/await 机制与 Tokio 运行时的核心原理。内容包括异步任务调度、Future 执行模型、并发安全、网络 IO 编程以及高并发场景下的性能优化。通过实战示例,帮助开发者使用 Rust 构建高性能、低延迟的后端服务与网络应用。

1

2026.02.11

Spring Boot企业级开发与MyBatis Plus实战
Spring Boot企业级开发与MyBatis Plus实战

本专题面向 Java 后端开发者,系统讲解如何基于 Spring Boot 与 MyBatis Plus 构建高效、规范的企业级应用。内容涵盖项目架构设计、数据访问层封装、通用 CRUD 实现、分页与条件查询、代码生成器以及常见性能优化方案。通过完整实战案例,帮助开发者提升后端开发效率,减少重复代码,快速交付稳定可维护的业务系统。

6

2026.02.11

包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法
包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法

本专题汇总了包子漫画官网和网页版入口,提供最新章节抢先看方法、正版免费阅读指南,以及稳定访问方式,帮助用户快速直达包子漫画页面,无广告畅享全集漫画内容。

159

2026.02.10

MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法
MC.JS网页版快速畅玩指南_MC.JS官网在线入口及免安装体验方法

本专题汇总了MC.JS官网入口和网页版快速畅玩方法,提供免安装访问、不同版本(1.8.8、1.12.8)在线体验指南,以及正版网页端操作说明,帮助玩家轻松进入MC.JS世界,实现即时畅玩与高效体验。

89

2026.02.10

谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程
谷歌邮箱网页版登录与注册全指南_Gmail账号快速访问与安全操作教程

本专题汇总了谷歌邮箱网页版的最新登录入口和注册方法,详细提供官方账号快速访问方式、网页版操作教程及安全登录技巧,帮助用户轻松管理Gmail邮箱账户,实现高效、安全的邮箱使用体验。

78

2026.02.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 16.8万人学习

Pandas 教程
Pandas 教程

共15课时 | 1.1万人学习

C# 教程
C# 教程

共94课时 | 9.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号