关于名称空间的一些事情

我在用PHP编程。 还有一点关于JS 。 一旦我用Java编程,就可以使用LotusScript 。 尝试了pythondart的味道。 BasicFortranPascalPrologVisualBasic++ / perl在所有这些上,我还描绘了一些可执行文件。 编程语言使我对创建计算机应用程序感兴趣。 Web应用程序。 复杂的Web应用程序。 那些写彼此不熟悉的人。 更准确地说,他们本人并不熟悉-通过提交到公共存储库的签名和通过错误跟踪器的昵称彼此了解。 我不太聪明,无法在各种操作系统的 / ++进行编程,因此我在PHPMagento进行编程。


因此,回到本文的主题,我可以说命名空间是非常重要的支柱之一,在此基础上,编写复杂的 Web应用程序是基于一群彼此不熟悉开发人员。


在本文中,就命名空间而言,我的意思是从PHP的角度来看命名空间 ,而不是从python的角度来看命名空间


 <?php namespace Vendor\Project\Module\Component\Unit; 

当我尝试理解“ package ”指令的秘密时,我第一次遇到了一个命名空间:


 package com.sun.source.util; 

该指令的目的尚不清楚,如果可以指示任何行,则应在其中确切指出。 来自该语言作者的建议(在您的公司域中)用作注册的软件包名称的一部分,看上去有些奢侈。 现在每个人,每个人,每个人都有自己的域名,这样的建议并不是很尴尬,而15到20年前,我非常考虑要使用哪个域名作为我的第一个软件包的名称,以及它将来可能会影响什么。 直到后来,当我使用maven构建应用程序时,我maven这一建议的见解感到赞赏。


依赖经理


依赖性管理器帮助我理解了名称空间的含义。 如果您的代码使用第三方代码,而第三方代码依赖于其他依赖第三方程序包的程序包,则很难在此类转储中维持顺序。 尽管如此,正是由于使用后域规则来命名堆在一个目录(例如,在WEB-INF/lib )中的一堆JAR中的软件包,所以导航起来非常容易:


图片


npmJavaScript )比较:


图片


Java开发人员相当广泛地采用了程序包的“ 后域 ”名称(由于模块),而在JS则没有。 因此,在Java您可以独立创建大量无冲突的程序包(模块),而无需明确同意它们的名称作为独立的开发组;在JS您必须明确地使用npm注册表 。 是的,在Java全局域注册表隐式地涉及解决冲突,但是任何社区(不仅仅是Java编码器)都可以使用相同的命名规则。


PHPcomposer依赖项管理器创建一个两级目录结构: ./company/module


图片


与单级分配相比,这在依赖项导航中提供了一些优势。


以下是Java / JS / PHP中央软件包存储库的统计信息:


https://mvnrepository.com/repos/central-3 358 578个索引罐
https://www.npmjs.com/-872459程序包
https://packagist.org/statistics-207560包(1,472,944版本)


对于maven最有可能的是,统计信息中会考虑所有模块版本,而npmcomposer会考虑模块本身。


命名空间是什么?


主要的答案是防止具有相同名称但在不同模块中的各种代码元素(常量,函数,类等)之间发生冲突。 Python名称空间成功地解决了这个问题。 但是我仍然在这里用引号将“命名空间”使用,因为 从本质上讲,它更接近范围


首先,根据Javapackage )和PHPnamespace )版本的namespace允许明确地寻址聚合社区中的特定代码元素。 这是名称空间(逻辑分组)的一个属性,它使得由开发者联系较少的组创建更复杂的软件系统成为可能。


寻址软件元素


PHP无论源代码如何连接到项目,都将唯一地寻址\Doctrine\DBAL\Schema\Column类。 IDE可以轻松地形成此地址。 在PhpStorm中,这是这样完成的(右键单击代码元素):


图片


如果您对JS代码(没有名称空间)应用类似的技术,则会丢失相同的PhpStorm。 让我们尝试以这种方式形成指向JS query函数的链接的地址:


图片


输出是module.query ,它的信息不足。


要解决文档中的query功能(信函,错误跟踪器等),您必须引用文件中的特定代码行:


图片


结果: ./node_modules/express/lib/middleware/query.js:25./node_modules/express/lib/middleware/query.js:25


当然,当更改文件中的行数或移动/重命名文件时,我们将在文档中提供我们感兴趣的程序元素的过时地址。


因此,使用名称空间可以使与项目代码的各个元素的链接比与文件中的行的链接保持相关的时间更长。


检测有冲突的代码版本


没有依赖管理器( mavencomposernpm ,...),就无法开发现代复杂的应用程序。 同时,我们的依赖关系会拉动它们的依赖关系,拉动自己的依赖关系,依此类推,结果可能导致同一包通过不同的依赖关系( jar hell )出现版本冲突。


JS由于缺少命名空间'ov而不会发生这种情况。 我自己遇到一种情况,当在Magento安装其他模块时,它们加载的jQuery库的不同版本数超过5-6。 一方面,这种行为为开发人员提供了更大的自由,另一方面,更多的自由对资格提出了更高的要求。 好吧,在如此多版本的依赖关系中寻找错误-限定条件比制造这些错误的限定条件要高一个或两个等级。


PHP使用名称空间可以很容易地在IDE级别检测到此类冲突(例如,我制作了另一个文件,其中包含该类的副本):


图片


因此,检测项目中重复代码元素的任务变得非常容易实现。


代码启动


PHPspl_autoload_register函数使开发人员不必费心去spl_autoload_register带有其类源的文件所在的位置。 在任何项目中,您都可以覆盖此函数,并按类名实现自己的脚本加载算法。 在不使用命名空间的情况下,有必要为类写出卷曲的名称,以确保它们在复杂项目中的唯一性(尤其是考虑到第三方库)。 在Zend1用于数据库Zend1抽象适配器定义如下:


 abstract class Zend_Db_Adapter_Abstract {} 

为了确保唯一性,从本质上讲,有必要在类名称中添加名称空间。 当然,在代码中使用此类名称时,您必须睁大眼睛。


Zend2 ,已经使用了名称空间,类似的类定义如下所示:


 namespace Zend\Db\Adapter; class Adapter implements ... {} 

代码最终变得更具可读性,但是使用名称空间的最重要结果是可以通过将类的逻辑层次结构绑定到文件结构来统一类加载器的功能。 以下是./vendor/composer/autoload_namespaces.php文件的摘录,该文件是composerPHP创建的,以使./vendor/autoload.php加载程序正常工作:


 <?php $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'Zend_' => array($vendorDir . '/magento/zendframework1/library'), 'Yandex' => array($vendorDir . '/allure-framework/allure-codeception/src', $vendorDir . '/allure-framework/allure-php-api/src', $vendorDir . '/allure-framework/allure-php-api/test'), 'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'), 'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src'), 'PhpCollection' => array($vendorDir . '/phpcollection/phpcollection/src'), 'PHPMD\\' => array($vendorDir . '/phpmd/phpmd/src/main/php'), 'OAuth\\Unit' => array($vendorDir . '/lusitanian/oauth/tests'), 'OAuth' => array($vendorDir . '/lusitanian/oauth/src'), ... 

可以看出,不同库中的源可以以不同的方式定位(不同的模块内部结构),并且composer在形成项目时会创建一个在文件系统上叠加类的逻辑层次结构的映射。 命名空间在此叠加层中起着重要作用。


要评估该角色,只需尝试将一些npm模块分解为几个较小的模块,然后重建项目以使用两个新模块,而不是一个大模块即可。 顺便说一句, ES6中类的存在以及代码逻辑分组的意义上缺少名称空间,可能会导致出现与大型ES6项目中的Zend1Module_Path_To_Class )类似的名称。


IoC


IoC容器中对象的标识符是一个字符串(至少在PHP )。 在简单的示例中,完全可以接受dbAdapterserviceAserviceB等标识符。 但是项目越大,就越难searchFilterList带有标识符的对象的创建位置,例如searchFilterList及其使用位置。 逻辑上的出路是使用类名作为对象的标识符。 在这种情况下,由容器创建对象的逻辑变得可以预测,并且源代码和使用位置由IDE进行基本确定。 命名空间使您可以在一个逻辑结构中组织所有项目类,并在使用容器创建对象时使用适当的路径。


总结


鉴于上述情况,我认为,与没有逻辑分组的语言相比,本机使用名称空间通过其元素的逻辑分组来自然地构造源代码的编程语言使您能够以更低的成本构建更复杂的应用程序。 因此,具有JavaScript / Python / C / ...相同资格的开发人员无法实现可以在Java / PHP / C++ / ...中创建的应用程序的最大复杂性。

Source: https://habr.com/ru/post/zh-CN434968/


All Articles