php判断ip地址正则表达式例子

 更新时间:2016年11月25日 15:41  点击:1561
在php中中有自定义函数可以帮我人判断IP地址,也有我们常用的正则函数来判断IP地址,下面我分别来给各位同学总结了验证IP地址的一些方法。

filter函数过滤ip地址的方法:

 代码如下 复制代码

echo filter_var("127.0.0.1","FILTER_VALIDATE_INT"); //返回true or false

例子。

判断是否是合法IP

 代码如下 复制代码

if(filter_var($ip, FILTER_VALIDATE_IP)) {
// it's valid
}
else {
// it's not valid
}

判断是否是合法的公共IPv4地址,192.168.1.1这类的私有IP地址将会排除在外

 代码如下 复制代码
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE)) {
// it's valid
}
else {
// it's not valid
}

判断是否是合法的IPv6地址

 代码如下 复制代码
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE)) {
// it's valid
}
else {
// it's not valid
}

判断是否是public IPv4 IP或者是合法的Public IPv6 IP地址

 代码如下 复制代码
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
// it's valid
}
else {
// it's not valid
}

简单的正则

preg_match("/d{1,3}.d{1,3}.d{1,3}.d{1,3}/");// 此方法没不精确,学最大为255.255.255.255 但这个只是验证格式了,如999.999.999.999也可以通过验证。

我们进入升级改进

 代码如下 复制代码

functionis_ip($gonten){ 
$ip=explode(”.”,$gonten); 
for($i=0;$i<count($ip);$i++) 

if($ip[$i]>255){ 
return(0); 


return ereg(”^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$”,$gonten); 
}

这样就符合我们的要求了

再介绍一种用判断ip地址:

 代码如下 复制代码


function matchip($q){
preg_match('/((25[0-5])|(2[0-4]d)|(1dd)|([1-9]d)|d)(.((25[0-5])|(2[0-4]d)|(1dd)|([1-9]d)|d)){3}/', $q, $matches);
return $matches[0];
}

$ipaddress = '201.103.2.2';
$iperror ='262.3.6.6';
$iptest = matchip( $ipaddress );
//当我们给matchip 的值为$ipaddress输出为201.103.2.2
//当我们给matchip的函数值为$iperror时,输出值为 62.3.6.6

if( $iptest )
{
 echo $iptest;
}
else
{
 echo 'www.111cn.net提示:你输的的ip地址有问题';
}

PHP从程序化到面向对象

 

范式局限

每种编程范式都限制了我们将想象转化为现实的能力。这些范式去掉了一部分可行方案,却纳入另一些方案作为替代,但这一切都是为了实现同样的表示效果。模块化编程令程序规模受到制约,强迫程序员只能在对应模块范畴之内施展拳脚,且每个模块结尾都要以“go-to”来指向其它模块。这种设定直接影响了程序成品的规模。另外,结构化编程与程序化编程方式去掉了“go-to”声明,从而限制了程序员对序列、选择以及迭代语句的调整能力。序列属于变量赋值,选择属于if-else判断,而迭代则属于do-while循环。这些已经成为当下编程语言与范式的构建基石。

面向对象编程方式去掉了函数指针,同时引入多态特性。PHP使用指针的方式与C语言有所不同,但我们仍能从变量函数库中找到这些函数指针的变体形式。这使得程序员能够将某个变量的值当成函数名称,从而实现以下内容:

function foo() {  
    echo "This is foo";  
}
function bar($param) {  
    echo "This is bar saying: $param";  
}  

$function = 'foo';  
$function();        // Goes into foo()  

$function = 'bar';  
$function('test');  // Goes into bar()

初看起来,这种特性似乎无关紧要。但仔细想想,大家一定会发现其中蕴含着极为强大的潜力。我们可以将一条变量作为参数发往某函数,然后让该函数根据参数数值调用其它函数。这绝对非同小可。它使我们能够在不了解函数功能的前提下对其进行调用,而且函数自身根本不会体现出任何差异。

这项技术也正是我们实现多态性调用的关键所在。

现在,我们姑且不谈函数指针的作用,先来看看其工作机制。函数指针中其实已经隐藏着“go-to”声明,或者至少以间接方式实现了与“go-to”相近的执行效果。这可不是什么好消息。事实上,PHP通过一种非常巧妙的方式在不直接使用的前提下实现“go-to”声明。如前例所示,我需要首先在PHP中做出声明。虽然这看起来不难理解,但在大型项目以及函数种类繁多且彼此关联的情况下,我们还是很难准确做出判断。而在C语言这边,这种关系就变得更加晦涩且极难理解。

然而仅仅消除函数指针还远远不够。面向对象的编程机制必然带来替代方案,事实也确实如此,它包含着多态特性与一套简单语法。重点来了,多态性正是面向对象编程的核心价值,即:控制流与源代码在依赖关系上正好相反。

wKioJlHahb2xCRl5AABIc_V8nMk597

 

在上面的图片中,我们描绘了一个简单的例子:多态性如何在两个不同范式之间发挥作用。在程序化或者结构化编程领域,控制流与源代码在依赖关系上非常相似——二者都指向更具体的输出行为。

而在面向对象编程方面,我们可以逆转源代码的依赖关系,使其指向抽象执行结果,并保持控制流仍旧指向具体执行结果。这一点至关重要,因为我们希望控制机制能尽可能触及具体层面与代码中的不稳定部分,这样我们才能真正让执行结果与预期相符。但在源代码这边,我们的要求却恰好相反。对于源代码,我们希望将具体结果与不稳定因素排除在外,从而简化修改流程、让改动尽量不影响其它代码。这样不稳定部分可以经常修正,但抽象部分则仍然有效。大家可以点击此处阅读由Robert C.Martin所撰写的依赖倒置原则研究论文。

试手任务

在本章中,我们将创建一款简单应用,旨在列出谷歌日程表及其事件提醒内容。首先,我们尝试利用程序化方式进行开发,只涉及简单功能、避免以任何形式使用类或对象。开发工作结束之后,我们更进一步、在不改动程序化代码的前提下通过行为进行代码整理。最后,尝试将其转化为面向对象版本。

谷歌PHP API客户端

谷歌专门针对PHP提供一套API客户端,我们将利用它与自己的谷歌账户进行对接,从而对日程表服务加以操作。要想让代码正确起效,大家需要通过设定让自己的谷歌账户接受来自日程表的查询。

虽然这是本篇指南文章的重要前提,但并不能算主要内容。为了避免在这方面浪费太多篇幅,请大家直接参考官方说明文档。各位不必担心,整个设置过程非常简单,而且只要五分钟左右即可搞定。

本教程附带的示例代码中包含谷歌PHP API客户端代码,建议大家就使用这一套以确保整个学习过程与文章说明保持一致。另外,如果大家想尝试自行安装,请点击此处查看官方说明文档。

接下来按照指示向apiAccess.php文件中填写信息。该文件在程序化与面向对象两套实例中都会用到,因此大家不必在新版本中重复填写。我在文件中留下了自己填写的内容,这样大家就能更轻松地找到对应位置并将其按自己的资料进行修改。

如果大家碰巧用的是NetBeans,我把各个项目文件保存在了包含有不同范例的文件夹当中。这样大家可以轻松打开该项目,并点选Run——>Run Project在本地PHP服务器(要求使用PHP 5.4)上直接加以运行。

与谷歌API对接的客户端库为面向对象型。为了示例的正常运行,我编写了一套小小的函数合集,其中囊括了本教程所需要的所有函数。通过这种方式,我们可以利用程序化层在面向对象客户端库之上进行软件编写,且代码不会涉及任何对象。

如果大家打算快速测试自己的代码与指向谷歌API的连接是否正常起效,则可以直接使用位于index.php文件中的代码。它会列出账户中所有日程表信息,且应该至少有一套具备summary字段的日程表中包含您的姓名。如果日程表中存在联系人生日信息,那么谷歌API将无法与之正常协作。不过大家不用惊慌,另选一套即可。

 

require_once './google-api-php-client/src/Google_Client.php';  
require_once './google-api-php-client/src/contrib/Google_CalendarService.php';  
require_once __DIR__ . '/../apiAccess.php';  
require_once './functins_google_api.php';  
require_once './functions.php';  
session_start();  

$client = createClient();  
if(!authenticate($client)) return;  
listAllCalendars($client);

 

这个index.php文件将成为我们应用程序的入口点。我们不会使用任何Web框架或者其它复杂的机制。我们要做的只是简单输出一些HTML代码而已。

程序化开发方案

现在我们已经了解了所需创建的目标以及所能使用的资源,接下来就是下载附件中的源代码。我会提供代码中的有用片段,但为了进一步了解全局情况,大家可能希望访问其初始来源。

在这套方案中,我们只求成果能按预期生效。我们的代码可能会显得有些粗糙,而且其中只涉及以下几个文件:

• index.php – 这是惟一一个我们需要通过浏览器直接访问并转向其GET参数的文件。

• functions_google_api.php – 囊括所有前面提到的谷歌API。

• functions.php – 一切奇迹在此发生。

functions.php将容纳应用程序的所有执行过程。包括路由逻辑、表现以及一切值与行为全部发生于此。这款应用非常简单,其主逻辑如下图所示:

wKioOVHahd2DhpXCAAA3KVHomR8310

 

这里有一项名为doUserAction()的函数,它的生效与否取决于一条很长的if-else声明;其它方法则根据GET变量中的参数决定调用情况。这些方法随后利用API与谷歌日程表对接,并在屏幕上显示出我们需要的任何结果。

function printCalendarContents($client) {  
   putTitle('These are you events for ' . getCalendar($client, $_GET['showThisCalendar'])['summary'] . ' calendar:');  
   foreach (retrieveEvents($client, $_GET['showThisCalendar']) as $event) {  
      print('
‘ . date(‘Y-m-d H:m’, strtotime($event['created']))); putLink(‘?showThisEvent=’ . htmlentities($event['id']) . ‘&calendarId=’ . htmlentities($_GET['showThisCalendar']), $event['summary']); print(‘

‘); print(‘
‘); } }

这个例子恐怕要算我们此次编写的代码中最为复杂的函数。它所调用的是名为putTitle()的辅助函数,其作用是将某些经过格式调整的HTML输出以充当标题。标题中将包含我们日程表的实际名称,这是通过调用来自functions_google_api.php文件中的getCalendar()函数来实现的。返回的日历信息是一个数组,其中包含一个summary字段,而这正是我们要找的内容。

$client变量被传递到我们的所有函数当中。它需要与谷歌API相连,不过这方面内容我们稍后再谈。

接下来,我们整理一下日程表中的全部现有事件。这份数组列表由封装在retrieveEvents()函数中的API请求运行得来。对于每个事件,我们都会显示出其创建日期及标题。

wKioOVHahfnBKnNbAABE8YrheVA192

 

其余部分代码与我们之前讨论过的内容相近,甚至更容易理解。大家可以抱着轻松的心情随便看看,然后抖擞精神进军下一章。

组织程序化代码

我们当前的代码完全没问题,但我想我们可以通过调整使其以更合适的方式组织起来。大家可能已经从附带的源代码中发现,该项目所有已经组织完成的代码都被命名为“GoogleCalProceduralOrganized”。

使用全局客户端变量

在代码组织工作中,第一件让人心烦的事在于,我们把$client变量作为参数推广到全局以及嵌套函数的深层当中。程序化编程方案对这类情况提供了一种巧妙的解决办法,即全局变量。由于$client是由index.php所定义,而从全局观点来看,我们需要改变的只是函数对该变量的具体使用方式。因此我们不必改变$client参数,而只需进行如下处理:

function printCalendars() {  
   global $client;  
   putTitle('These are your calendars:');  
   foreach (getCalendarList($client)['items'] as $calendar) {  
      putLink('?showThisCalendar=' . htmlentities($calendar['id']), $calendar['summary']);  
      print('
');  
   }  
}

大家不妨将现有代码与附件中的代码成品进行比较,看看二者有何不同之处。没错,我们并没有将$client作为参数传递,而是在所有函数中使用global $client并将其作为只传递向谷歌API函数的参数。从技术角度看,即使是谷歌API函数也能够使用来自全局的$client变量,但我认为最好还是尽量保持API的独立性。

从逻辑中分离表示

某些函数的作用非常明确——只用于在屏幕上输出信息,但有些函数则用于判断触发条件,更有些函数身兼两种作用。面对这种情况,我们往往最好把这些存在特殊用途的函数放在属于自己的文件当中。我们首先整理只用于屏幕信息输出的函数,并将其转移到functions_display.php文件当中。具体做法如下所示:

function printHome() {  
   print('Welcome to Google Calendar over NetTuts Example');  
}  

function printMenu() {  
   putLink('?home', 'Home');  
   putLink('?showCalendars', 'Show Calendars');  
   putLink('?logout', 'Log Out');  
   print('

');  
}  

function putLink($href, $text) {  
   print(sprintf('%s | ', $href, $text));  
}  

function putTitle($text) {  
   print(sprintf('

%s

‘, $text)); } function putBlock($text) { print(‘

‘.$text.’

‘); }

要完成剩余的表示分离工作,我们需要从方法中提取出表示部分。下面我们就以单一方法为例演示这一过程:

function printEventDetails() {  
   global $client;  
   foreach (retrieveEvents($_GET['calendarId']) as $event)  
      if ($event['id'] == $_GET['showThisEvent']) {  
         putTitle('Details for event: '. $event['summary']);  
         putBlock('This event has status ' . $event['status']);  
         putBlock('It was created at ' .  
               date('Y-m-d H:m', strtotime($event['created'])) .  
               ' and last updated at ' .  
               date('Y-m-d H:m', strtotime($event['updated'])) . '.');  
         putBlock('For this event you have to ' . $event['summary'] . '.');  
      }  
}

我们可以明显看到,无论if声明中的内容如何、其代码都属于表示代码,而余下的部分则属于业务逻辑。与其利用一个庞大的函数处理所有事务,我们更倾向于将其拆分为多个不同函数:

function printEventDetails() {  
   global $client;  
   foreach (retrieveEvents($_GET['calendarId']) as $event)  
      if (isCurrentEvent($event))  
         putEvent($event);  
}  

function isCurrentEvent($event) {  
   return $event['id'] == $_GET['showThisEvent'];  
}

分离工作完成后,业务逻辑就变得简单易懂了。我们甚至提取了一个小型方法来检测该事件是否就是当前事件。所有表示代码现在都由名为putEvent($event)函数负责,且被保存在functions_display.php文件当中:

function putEvent($event) {  
   putTitle('Details for event: ' . $event['summary']);  
   putBlock('This event has status ' . $event['status']);  
   putBlock('It was created at ' .  
         date('Y-m-d H:m', strtotime($event['created'])) .  
         ' and last updated at ' .  
         date('Y-m-d H:m', strtotime($event['updated'])) . '.');  
   putBlock('For this event you have to ' . $event['summary'] . '.');  
}

尽管该方法只负责显示信息,但其功能仍需在对$event结构非常了解的前提下方能实现。不过对于我们的简单实例来说,这已经足够了。对于其余方法,大家可以通过类似的方式进行分离。

清除过长的if-else声明

目前代码整理工作还剩下最后一步,也就是存在于doUserAction()函数中的过长if-else声明,其作用是决定每项行为的实际处理方式。在元编程方面(通过引用来调用函数),PHP具备相当出色的灵活性。这种特性使我们能够将$_GET变量的值与函数名称关联起来。如此一来,我们可以在$_GET变量中引入单独的action参数,并将该值作为函数名称。

function doUserAction() {  
   putMenu();  
   if (!isset($_GET['action'])) return;  
      $_GET['action']();  
}

基于这种方式,我们生成的菜单将如下所示:

function putMenu() {  
   putLink('?action=putHome', 'Home');  
   putLink('?action=printCalendars', 'Show Calendars');  
   putLink('?logout', 'Log Out');  
   print('

');  
}

如大家所见,经过重新整理之后,代码已经呈现出面向对象式设计的特性。虽然目前我们还不清楚其面向的是何种对象、会执行哪些确切行为,但其特征已经初露端倪。

我们已经让来自业务逻辑的数据类型成为表示的决定性因素,其效果与我们在文首介绍环节中谈到的依赖倒置机制比较类似。控制流的方向仍然是从业务逻辑指向表示,但源代码依赖性则与之相反。从这一点上看,我认为整套机制更像是一种双向依赖体系。

设计倾向上的面向对象化还体现在另一个方面,即我们几乎没有涉及到元编程。我们可以调用一个方法,但却对其一无所知。该方法可以拥有任何内容,且过程与处理低级多态性非常相近。

依赖性分析

对于当前代码我们可以绘制出一份关系图,内容如下所示。通过这幅关系图,我们可以看到应用程序运行流程的前几个步骤。当然,把整套流程都画下来就太过复杂了。

wKioOVHahiLDcBxKAACPYiN035k571

蓝色线条代表程序调用。如大家所见,这些线条与始终指向同一个方向。图中的绿色线条则表示间接调用,可以看到所有间接调用都要经过doUserAction()函数。这两种线条代表控制流,显然控制流的走向基本不变。

红色线条则引入了完全不同的概念,它们代表着最初的源代码依赖关系。之所以说“最初”,是因为随着应用的运行其指向将变得愈发复杂、难以把握。putMenu()方法中包含着被特定关系所调用的函数的名称。这是一种依赖关系,同时也是适用于所有其它关系创建方法的基本规则。它们的具体关系取决于其它函数的行为。

上图中我们还能看到另一种依赖关系,即对数据的依赖。我前面曾经提到过$calendar与$event,输出函数需要清楚了解这些数组的内部结构才能实现既定功能。

完成了以上内容之后,我们已经做好充分准备、可以迎来本篇教程中的最后一项挑战。

面向对象解决方案

无论采用哪种范式,我们都不可能为问题找到完美的解决方案。因此以下代码组织方式仅仅属于我的个人建议。

从直觉出发

我们已经完成了业务逻辑与表现的分离工作,甚至将doUserAction()方法作为一个独立单元。那么我的直觉是先创建三个类,Presenter、Logic与Router。三者以后可能都需要进行调整,但我们不妨先从这里着手,对吧?

Router中将只包含一个方法,且实现方式与之前提到的方法非常相似。

class Router {  

   function doUserAction() {  
      (new Presenter())->putMenu();  
      if (!isset($_GET['action']))  
         return;  
      (new Logic())->$_GET['action']();  
   }  

}

现在我们要做的是利用刚刚创建的Presenter对象调用putMenu()方法,其它行为则利用Logic对象加以调用。不过这样会马上产生问题——我们的一项行为并不包含在Logic类当中。putHome()存在于Presenter类中,我们需要在Logic中引入一项行为,借以在Presenter中作为putHome()方法的委托。请记住,目前我们要做的只是将现有代码整理到三个类当中,并将三者作为面向对象设计的备选对象。现在所做的一切只是为了让设计方案能够正常运作,待代码编写完成后、我们将进一步加以调试。

在将putHome()方法引入Logic类后,我们又遇上新的难题。怎样才能从Presenter中调用方法?我们可以创建一个Presenter对象,并将其传递至Logic当中。下面我们从Router类入手。

class Router {  

   function doUserAction() {  
      (new Presenter())->putMenu();  
      if (!isset($_GET['action']))  
         return;  
      (new Logic(new Presenter))->$_GET['action']();  
   }  

}

现在我们可以向Logic添加一个构造函数,并将其添加到Presenter内指向putHome()的委托当中。

class Logic {  

   private $presenter;  

   function __construct(Presenter $presenter) {  
      $this->presenter = $presenter;  
   }  

   function putHome() {  
      $this->presenter->putHome();  
   }  

[...]  

}

通过对index.php的一些小小调整、让Presenter包含原有display方法、Logic包含原有业务逻辑函数、Router包含原有行为选择符,我们已经可以让自己的代码正常运行并具备“Home”菜单元素。

require_once './google-api-php-client/src/Google_Client.php';  
require_once './google-api-php-client/src/contrib/Google_CalendarService.php';  
require_once __DIR__ . '/../apiAccess.php';  
require_once './functins_google_api.php';  
require_once './Presenter.php';  
require_once './Logic.php';  
require_once './Router.php';  
session_start();  

$client = createClient();  
if(!authenticate($client)) return;  

(new Router())->doUserAction();

下面就是其执行效果。
wKioOVHahjzDEpEpAAApNMp4wc8140

接下来,我们需要在Logic类中适当变更指向display逻辑的调用指令,从而与$this->presenter相符。现在我们有两个方法——isCurrentEvent()与retrieveEvents()——二者只被用于Logic类内部。我们将其作为专用方法,并据此变更调用关系。

下面我们对Presenter类进行同样处理,并将所有指向方法的调用都变更为指向$this->something。由于putTitle()、putLink()与putBlock()都只由Presenter使用,因此需要将其变为专用。如果感到上述变更过程难于理解及操作,请大家查看附件源代码内GoogleCalObjectOrientedInitial文件夹中的已完成代码。

现在我们的应用程序已经能够正常运行,这些按面向对象语法整理过的程序化代码仍然使用$client全局变量,且拥有大量其它非面向对象式特性——但仍然能够正常运行。

如果要为目前的代码绘制依赖关系类图,则应如下所示:

wKioJlHahkmR5N0sAABF76hGdDo031

 

控制流与源代码的依赖关系都通过Router、然后是Logic、最后通过表示层。最后一步变更削弱了我们在之前步骤中所观察到的依赖倒置特性,但大家千万不要因此受到迷惑——原理依然如故,我们要做的是使其更加清晰。

恢复源代码依赖关系

很难界定基础性原则之间哪一条更重要,但我认为依赖倒置原则对我们的应用设计影响最大也最直接。该原则规定:

A:高层模块不应依赖于低级模块,二者都应依赖于抽象。

B:抽象不应依赖于细节,细节应依赖于抽象。

简单来说,这意味着具体实施应依赖于抽象类。类越趋近抽象,它们就越不容易发生改变。因此我们可以这样理解:变更频繁的类应依赖于其它更为稳定的类。所以任何应用中最不稳定的部分很可能是用户界面,这在我们的应用示例中通过Presenter类来实现。让我们再来明确一下依赖倒置流程。

首先,我们让Router仅使用Presenter,并打破其对Logic的依赖关系。

class Router {  

   function doUserAction() {  
      (new Presenter())->putMenu();  
      if (!isset($_GET['action']))  
         return;  
      (new Presenter())->$_GET['action']();  
   }  

}

然后我们变更Presenter,使其使用Logic实例并由此获取需要的信息。在我们的例子中,我认为由Presenter来建立该Logic实例也可以接受,但在生产系统当中、大家可能通常会利用Factories来创建与对象相关的业务逻辑,并将其注入表示层当中。

现在,原本同时存在于Logic与Presenter两个类中的putHome()函数将从Logic中消失。这一现象说明我们已经开始进行重复数据清除工作。指向Presenter的构造函数与引用也从Logic中消失了。另一方面,由构造函数所创建的Logic对象则必须被写入Presenter。

class Presenter {  

   private $businessLogic;  

   function __construct() {  
      $this->businessLogic = new Logic();  
   }  

   function putHome() {  
      print('Welcome to Google Calendar over NetTuts Example');  
   }  

[...]  

}

以上变更完成之后,点击Show Calendars,屏幕上会出现错误提示。由于我们链接内部的所有行为都指向Logic类中的函数名称,因此必须通过更多一致性调整来恢复二者之间的依赖关系。下面我们对方法进行一一修改,先来看第一条错误信息:

Fatal error: Call to undefined method Presenter::printCalendars()  
in /[...]/GoogleCalObjectOrientedFinal/Router.php on line 9

我们的Router希望调用Presenter中某个并不存在的方法,也就是printCalendars()。我们在Presenter中创建这样一个方法,并检查它会对Logic造成哪些影响。在结果中大家可以看到,它输出了一条标题,并在重复循环之后再次调用putCalendars()。在Presenter类中,printCalendars()方法如下所示:

function printCalendars() {  
   $this->putCalendarListTitle();  
   foreach ($this->businessLogic->getCalendars() as $calendar) {  
      $this->putCalendarListElement($calendar);  
   }  
}

在Logic方面,该方法则非常单纯——直接调用谷歌API库。

function getCalendars() {  
   global $client;  
   return getCalendarList($client)['items'];  
}

这可能让大家心中出现两个问题,“我们真的需要Logic类吗?”以及“我们的应用程序是否存在任何逻辑?”好吧,目前我们还不知道答案,现在能做的只是继续上述过程,直到所有代码都能正常工作且Logic不再依赖于Presenter。

接下来,我们将使用Presenter中的printCalendarContents()方法,如下所示:

function printCalendarContents() {  
   $this->putCalendarTitle();  
   foreach ($this->businessLogic->getEventsForCalendar() as $event) {  
      $this->putEventListElement($event);  
   }  
}

这将反过来允许我们简化Logic中的getEventsForCalendar(),并将其转化为如下形式:

function getEventsForCalendar() {  
   global $client;  
   return getEventList($client, htmlspecialchars($_GET['showThisCalendar']))['items'];  
}

现在应用已经不再报错,但我却又发现了新的问题。$_GET变量同时被Logic与Presenter类所使用——$_GET应该只被Presenter类使用才对。我的意思是,由于需要创建用于填充$_GET变量的链接,Presenter是肯定需要感知$_GET的。这就意味着$_GET与HTTP密切相关。现在,我们希望自己的代码能与命令行或者桌面图形用户界面协同运作。
因此我们需要保证只有Presenter感知到这一情况,即将以上两个方法变换为下列内容:

function getEventsForCalendar($calendarId) {  
   global $client;  
   return getEventList($client, $calendarId)['items'];  
}  
function printCalendarContents() {  
   $this->putCalendarTitle();  
   $eventsForCalendar = $this->businessLogic->getEventsForCalendar(htmlspecialchars($_GET['showThisCalendar']));  
   foreach ($eventsForCalendar as $event) {  
      $this->putEventListElement($event);  
   }  
}

现在我们需要实现特定事件的输出功能。对于本文中的范例,我们假设自己无法直接检索任何事件,即必须亲自进行事件查找。Logic类这时候就要派上用场了,我们可以在其中操作事件列表并搜索特定ID:

function getEventById($eventId, $calendarId) {  
   foreach ($this->getEventsForCalendar($calendarId) as $event)  
      if ($event['id'] == $eventId)  
         return $event;  
}

然后Presenter的对应调用会完成输出工作:

function printEventDetails() {  
   $this->putEvent(  
      $this->businessLogic->getEventById(  
         $_GET['showThisEvent'],  
         $_GET['calendarId']  
      )  
   );  
}

就是这样,我们已经成功完成了依赖倒置。

wKioJlHahnuSbo_GAABwHer8NOw282

 

控制流仍然由Logic指向Presenter,所有输出内容也完全由Logic进行定义。这样如果我们打算接入其它日程表服务,则只需创建另一个Logic类并将其注入Presenter即可,Presenter本身不会感知到任何差异。再有,源代码依赖关系也被成功倒置。Presenter是惟一创建且直接依赖于Logic的类。这种依赖关系对于保证Presenter可随意变更数据显示方式而又不影响Logic内容而言至关重要。此外,这种依赖关系允许我们利用CLI Presenter或者其它任何向用户显示信息的方法来替代HTML Presenter。

摆脱全局变量

现在惟一漏网的潜在设计缺陷就只剩下$client全局变量了。应用程序中的所有代码都会对其进行访问,但与之形成鲜明对比的是,真正有必要访问$client的只有Logic类一个。最直观的解决办法肯定是使其变更为专用类变量,但这样一来我们就需要将$client经由Router传递至Presenter处,从而使presenter能够利用$client变更创建出Logic对象——这对于解决问题显然无甚作用。我们的设计初衷是在独立环境下建立类,并准确为其分配依赖关系。

对于任何大型类结构,我们都倾向于使用Factories;但在本文的小小范例中,index.php文件已经足以容纳逻辑创建了。作为应用程序的入口点,这个类似于高层体系结构中“main”的文件仍然处于业务逻辑的范畴之外。

因此我们将index.php中的代码变更为以下内容,同时保留所有内容以及session_start()指令:

$client = createClient();  
if(!authenticate($client)) return;  

$logic = new Logic($client);  
$presenter = new Presenter($logic);  
(new Router($presenter))->doUserAction();

结语

现在工作彻底完成了。当然,我们的设计肯定还有很多改进的空间。我们可以为Logic类中的方法编写一些测试流程,也许Logic类本身也可以换个更有代表性的名称,例如GoogleCalendarGateway。我们还可以创建Event与Calendar类,从而更好地控制相关数据及行为,同时将Presenter的依赖关系根据数据类型拆分为数组。另一项改进与扩展方针则是创建多态性行为类,用于取代直接通过$_GET调用函数。总而言之,对于这一范例的改进可谓无穷无尽,有兴趣的朋友可以尝试将自己的想法转化为现实。我在附件的GoogleCalObjectOrientedFinal文件夹中保存有代码的最终版本,大家能够以此为起点进行探索。

如果大家的好奇心比较强,也可以试着将这款小应用与其它日程表服务对接,看看如何在不同平台上以不同方式实现信息输出。对于使用NetBeans的朋友,每个源代码文件夹中都包含有NetBeans项目,大家只要直接打开即可。在最终版本中,PHPUnit也已经准备就绪。不过我在其它项目中将其移除了——因为还没有经过测试。

JSOND:一个更优的PHP JSON解析器我光说优秀也没有,下面我来给各位演示几个例子吧,这会你看了就知道是不是优秀了哦。

首先,我们先来看看性能测试数据:

 代码如下 复制代码

STR: {"i": 23, "array": [1, null, false, true, ["aha", "baba", 23, {"test": 23}]]}
JSON:  time for 100000 iterations: 0.238321
JSOND: time for 100000 iterations: 0.236436

STR: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
JSON:  time for 100000 iterations: 0.110764
JSOND: time for 100000 iterations: 0.134212

STR: {"a": 23.2234232}
JSON:  time for 100000 iterations: 0.078458
JSOND: time for 100000 iterations: 0.055479

STR: {"long-str": "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.", }
JSON:  time for 100000 iterations: 0.881429
JSOND: time for 100000 iterations: 0.118529

STR: ... json_encode($_SERVER)
JSON:  time for 100000 iterations: 4.341252
JSOND: time for 100000 iterations: 1.960814

可以看到在大数据量的时候jsond的速度比json快多了。

项目地址:

Github:https://github.com/bukka/php-jsond

PECL:http://pecl.php.net/package/jsond

根据自身情况,选择相应的安装方法,安装成功后,查看phpinfo:

 

非常优秀 PHP JSON解析器程序

使用方法:

 代码如下 复制代码

mixed jsond_decode ( string $json [, bool $assoc = false [, int $depth = 512 [, int $options = 0 ]]] );
string jsond_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] );
string jsond_last_error_msg ( void );
int jsond_last_error ( void );

如果我们要判断访问网站的是手机用户还是PC用户我们只要获取用户的HTTP_USER_AGENT即可,我先介绍了一个通用的Mobile_Detect,后面两个例子是自己写的希望对各位有帮助。

php代码

 代码如下 复制代码

//使用实例

include 'Mobile_Detect.php';
$detect = new Mobile_Detect();

// Check for any mobile device.
if ($detect->isMobile())

// Check for any tablet.
if($detect->isTablet())

// Check for any mobile device, excluding tablets.
if ($detect->isMobile() && !$detect->isTablet())

if ($detect->isMobile() && !$detect->isTablet())

// Alternative to $detect->isAndroidOS()
$detect->is('AndroidOS');

// Batch usage
foreach($userAgents as $userAgent){
  $detect->setUserAgent($userAgent);
  $isMobile = $detect->isMobile();
}

// Version check.
$detect->version('iPad'); // 4.3 (float)


php判断手机访问

 代码如下 复制代码

ua = strtolower($_SERVER['HTTP_USER_AGENT']);

$uachar = "/(nokia|sony|ericsson|mot|samsung|sgh|lg|philips|panasonic|alcatel|lenovo|cldc|midp|mobile|wap)/i";

if(($ua == '' || preg_match($uachar, $ua))&& !strpos(strtolower($_SERVER['REQUEST_URI']),'wap'))
{
    $Loaction = 'wap/';

    if (!empty($Loaction))
    {
        ecs_header("Location: $Loactionn");

        exit;
    }

}

 

/** 
* 自定义 header 函数,用于过滤可能出现的安全隐患 

* @param   string  string  内容 

* @return  void 
**/ 
function ecs_header($string, $replace = true, $http_response_code = 0) 

    if (strpos($string, '../upgrade/index.php') === 0) 
    { 
        echo '<script type="text/javascript">window.location.href="' . $string . '";</script>'; 
    } 
    $string = str_replace(array("r", "n"), array('', ''), $string); 
 
    if (preg_match('/^s*location:/is', $string)) 
    { 
        @header($string . "n", $replace); 
 
        exit(); 
    } 
 
    if (emptyempty($http_response_code) || PHP_VERSION < '4.3') 
    { 
        @header($string, $replace); 
    } 
    else   www.111cn.net
    { 
        @header($string, $replace, $http_response_code); 
    } 

js代码

测试代码:

 代码如下 复制代码

var isIPhone = /iPhone/i.test(navigator.userAgent),
 isIPad = /iPad/i.test(navigator.userAgent),
 isAndroid = /android/i.test(navigator.userAgent);
var isIOS = isIPhone  || isIPad;
alert(
 "iPhone? "+isIPhone+"tr"+
 "iPad? "+isIPad+"tr"+
 "Android? "+isAndroid+"tr"+
 "iOS? "+isIOS
);

在PHP中,用你认为最简洁的方法把驼峰样式的字符串转换成下划线样式的字符串。例:输入是FooBar的话,输出则是foo_bar。

自己在看到这个问题的时候,想到的是用ASCII码来处理,没往万能的正则上去想。好吧,下面来看看答案:

答案1:

 代码如下 复制代码

$str = 'OpenAPI';

$length = mb_strlen($str);

$new = '';

for($i = 0; $i < $length; $i++)
{
 $num = ord($str[$i]);
 $pre = ord($str[$i - 1]);

 $new .= ($i != 0 && ($num >= 65 && $num <= 90) && ($pre >= 97 && $pre <= 122)) ? "_{$str[$i]}" : $str[$i];
} www.111cn.net

echo strtolower($new) . '<br>';

答案2:

 代码如下 复制代码

echo strtolower(preg_replace('/((?<=[a-z])(?=[A-Z]))/', '_', $str)).'<br>';

那反过来下划线分割字符串转换成驼峰式字符串怎么搞呢

 代码如下 复制代码

f = new File("d:/temp/t.txt")
if(f.exists()){
    f.eachLine{ line->
        line = line.trim()
        String[] elems = line.split('_')
        for(int i = 0; i < elems.length; i++){
            elems[i] = elems[i].toLowerCase()
            if(i != 0){
                String elem = elems[i]
                char first = elem[0] as char
                elems[i] = "" + (char)(first - 32) + elem.substring(1)
            }
        }
        println elems.join()
    }
}

[!--infotagslink--]

相关文章

  • PHP正则表达式取双引号内的内容

    取双引号内的内容我们如果一个字符串中只有一个可以使用explode来获得,但如果有多个需要使用正则表达式来提取了,具体的例子如下。 写程序的时候总结一点经验,如何只...2016-11-25
  • PHP正则表达式之捕获组与非捕获组

    今天遇到一个正则匹配的问题,忽然翻到有捕获组的概念,手册上也是一略而过,百度时无意翻到C#和Java中有对正则捕获组的特殊用法,搜索关键词有PHP时竟然没有相关内容,自己试了一下,发现在PHP中也是可行的,于是总结一下,分享的同...2015-11-08
  • php 验证只能输入汉字、英语、数字的正则表达式

    正则表达式是一门非常有用的并且进行模糊判断的一个功能了,我们下面来看通过正则来验证输入汉字、英语、数字,具体如下。 收藏了正则表达式。可以验证只能输入数...2016-11-25
  • java正则表达式判断前端参数修改表中另一个字段的值

    这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
  • 常用的日期时间正则表达式

    常用的日期时间正则表达式 下面收藏了大量的日期时间正则匹配函数,包括分钟,时间与秒都能达到。 正则表达式 (?n:^(?=d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(...2016-11-25
  • PHP正则表达式匹配验证提取网址URL实例总结

    网址规则是可寻的,所以我们可以使用正则表达式来提取字符串中的url地址了,下面一起来看看小编整理的几个PHP正则表达式匹配验证提取网址URL实例. 匹配网址 URL 的...2016-11-25
  • 正则表达式中两个反斜杠的匹配规则详解

    这篇文章主要介绍了正则表达式中两个反斜杠的匹配规则,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-07
  • JS中使用正则表达式g模式和非g模式的区别

    这篇文章给大家详细介绍了JS中使用正则表达式g模式和非g模式的区别,非常不错,具有参考借鉴价值,需要的朋友参考下吧...2017-04-03
  • JavaScript利用正则表达式替换字符串中的内容

    本文主要介绍了JavaScript利用正则表达式替换字符串中内容的具体实现方法,并做了简要注释,便于理解。具有一定的参考价值,需要的朋友可以看下...2017-01-09
  • C#正则表达式使用方法示例

    这篇文章主要介绍了C#正则表达式使用方法,大家参考使用...2020-06-25
  • 常用C#正则表达式汇总介绍

    c#正则表达式,用于字符串处理、表单验证等场合,实用高效。现将一些常用的表达式收集于此,以备不时之需。...2020-06-25
  • 一文秒懂python正则表达式常用函数

    这篇文章主要介绍了python正则表达式常用函数及使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-07
  • Idea使用正则表达式批量替换字符串的方法

    这篇文章给大家介绍了Idea使用正则表达式批量替换字符串的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧...2021-07-21
  • PHP正则表达式之捕获组与非捕获组

    今天遇到一个正则匹配的问题,忽然翻到有捕获组的概念,手册上也是一略而过,百度时无意翻到C#和Java中有对正则捕获组的特殊用法,搜索关键词有PHP时竟然没有相关内容,自己试了一下,发现在PHP中也是可行的,于是总结一下,分享的同...2015-11-08
  • C# 中使用正则表达式匹配字符的含义

    正则表达式的作用用来描述字符串的特征。本文重点给大家介绍C# 中使用正则表达式匹配字符的含义,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧...2020-06-25
  • Python验证的50个常见正则表达式

    这篇文章主要给大家介绍了关于利用Python验证的50个常见正则表达式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-11
  • C#编程自学之运算符和表达式

    这篇文章主要介绍了C#运算符和表达式,这是自学C#编程的第五篇,希望对大家的学习有所帮助。...2020-06-25
  • PHP正则表达式过滤html标签属性(DEMO)

    这篇文章主要介绍了PHP正则表达式过滤html标签属性的相关内容,实用性非常,感兴趣的朋友参考下吧...2016-05-06
  • js用正则表达式筛选年月日的实例方法

    在本篇文章里小编给大家整理的是一篇关于js用正则表达式筛选年月日的实例方法,对此有兴趣的朋友们可以学习下。...2021-01-04
  • javascript 手机号码正则表达式验证函数 <font color=red>原创</font>

    随着手机号码段的不断增加,以前网上的手机号码验证函数都不能那么完美的支持了,这里脚本之家编辑特为大家准备的一个简单的正则与手机验证的函数分析。...2021-05-07