将项目升级到PHP命名空间: 一个简单的解决方案

分享于 

8分钟阅读

Web开发

  繁體 雙語

介绍

在本文中,我们将解释为什么在我们的web应用程序项目中实现和实现 PHP。 几乎所有的这些都基于它,在 Scavix Web开发框架插件中实现,所以你将在那里找到完整的代码。 如果你不熟悉它,你可能需要先阅读我们的其他文章:

观众

具有扎实PHP知识的有经验的软件开发人员。

问题

你可能自己体验过了 将第三方库包含到项目中,它使用你在项目( 常见名称等'记录器'或者或或者'模型') 中使用的某些类型。
如果你不能改变你的名字,因为。of is。

  • 。向后兼容。
  • 。数据库中的外部类引用。

如果你不能改变第三方库,那就更糟了,因为它是 换句话说,封闭源码( 无论什么原因)。 在这种情况下,你将无法使用这里库,然后。

解决办法是什么呢

简短版本:在代码中使用命名空间。 更详细:如果将代码封装到命名空间中,你可以使用任何不使用相同名称空间的库。 当然,这样的冲突更不可能,如果你选择了正确的名称空间,( 像 CompanyNameProductName ) 将永远不会发生。

解决方案的问题

像往常一样,在使用干净的名称空间之前,有一些。 如果你从零开始,从零开始,则不存在,但请记住: 如果你与第三方库发生冲突,因此你处理现有项目。 如果向文件中添加命名空间,则需要在整个项目中进行。 它会崩溃直到你完成它。 这不太好,你可能会忘记一些地方,所以名称空间重新设计会带你很多时间。 但这是值得的。

解决解决方案中的问题

简而言之:向后兼容。 当然不是那么简单。 等等,事实上,在这种情况下 ! 哦,再次等待:只有在你使用自动加载,但我们确信,我们会继续:

基本过程是创建一个类别名( 如果请求的类是纯的但找到的类有一个限定的NAME )。 很酷吧在这个例子中我们来看看:?


//file: myclass.php


namespace ScavixSomeCoolProject;


class MyClass { /* some magic happens here */ }



这是classnames的标准自动载入机制:

// file: autoloader.php


function system_spl_autoload($class_name)


{


 // use some function to find the file that declares the class requested


 $file = __search_file_for_class($class_name);


 require_once($file);


}


spl_autoload_register("system_spl_autoload",true,true);



参考: __search_file_for_classspl_autoload_register。


// file: index.php


require_once("autoloader.php");


$mc = new MyClass(); // Throws an exception: Class not found


$mc = new ScavixSomeCoolProjectMyClass(); // OK



当然,在这个示例中需要'找不到类'异常。 为了使代码工作正常,现在我们将扩展自动加载程序,以便自动实现上述规则: 如果请求的类是纯的,但找到的类具有限定名,则创建类别名。


// file: autoloader_ex.php


function system_spl_autoload($class_name)


{


 if( strpos($class_name, '')!== false )


 {


 $orig = $class_name;


 $class_name = array_pop(explode('',$class_name));


 }


//use some function to find the file that declares the class requested


 $file = __search_file_for_class($class_name);



//remember the defined classes, include the $file and detect newly declared classes


 $pre = get_declared_classes();


 require_once($file);


 $post = array_unique(array_diff(get_declared_classes(), $pre));



//loop through the new class definitions and create weak aliases if they are given with qualified names


 foreach( $post as $cd )


 {


 $d = explode('',$cd);


 if( count($d)> 1 )


 {


//Aliasing full qualified classnames to their simple ones. Note: weak alias!


 create_class_alias($cd,array_pop($d));


 }


 }



//get the class definition. note: we assume that there's only one class/interface in each file!


 $def = array_pop($post);


 if(!isset($orig) &&!$def )


 // plain class requested AND file was already included, so search up the declared classes and alias


 {


 foreach( array_reverse($pre) as $c )


 {


 if(!ends_with($c,$class_name) )


 continue;


 // Aliasing previously included class


 create_class_alias($c,$class_name,true);


 break;


 }


 }


 else


 {


 $class_name = isset($orig)?$orig:$class_name;


 if( strtolower($def)!= strtolower($class_name) && ends_iwith($def,$class_name) )


 // no qualified classname requested but class was defined with namespace


 {


 // Aliasing class


 create_class_alias($def,$class_name,true);


 }


 }


}


spl_autoload_register("system_spl_autoload",true,true);



function create_class_alias($original,$alias,$strong=false)


{


 // if strong create a real alias known to PHP


 if( $strong )


 class_alias($original,$alias);



 // In any case store the alias in a global variable


 $alias = strtolower($alias);


 if( isset($GLOBALS['system_class_alias'][$alias]) )


 {


 if( $GLOBALS['system_class_alias'][$alias] == $original )


 return;



 if(!is_array($GLOBALS['system_class_alias'][$alias]) )


 $GLOBALS['system_class_alias'][$alias] = array($GLOBALS['system_class_alias'][$alias]);


 $GLOBALS['system_class_alias'][$alias][] = $original;


 }


 else


 $GLOBALS['system_class_alias'][$alias] = $original;


}



get_declared_classesends_with,ends_iwith。

行,比原来的行多一些,但不太复杂,对? )。现在这将正常工作:


// file: index.php


require_once("autoloader_ex.php");


$mc = new MyClass(); // OK


$mc = new ScavixSomeCoolProjectMyClass(); // OK



因此现在你可以将项目部分迁移到使用命名空间,而不必担心由于缺少名称空间声明而导致崩溃。 抱歉除去了忽略命名空间的最后一个借口:)

命名空间中的一些词

你可能已经注意到: 我们喜欢命名空间但是你必须对它做正确的操作,并考虑它是否有用。 因此,我们在项目中遵循这些规则:

  • 使用的唯一命名空间 root
  • 每个文件只使用个名称空间
  • 确保每个类/接口的在命名空间
  • 在每个类/接口中放入的,
  • 将函数添加到命名空间

更改日志

  • 2013/08/26: 初始发布

相关文章