Etwas über den Namespace

Ich programmiere in PHP . Und ein bisschen über JS . Einmal in Java programmiert, noch früher - in LotusScript . Versuchte einen Geschmack von python und dart . Basic , Fortran , Pascal , Prolog , VisualBasic , ++ / , perl - auf all dem habe ich auch etwas ausführbares dargestellt. Programmiersprachen interessieren mich für die Erstellung von Computeranwendungen. Webanwendungen. Anspruchsvolle Webanwendungen. Diejenigen, die Menschen schreiben, die sich nicht kennen. Genauer gesagt sind sie persönlich unbekannt - sie kennen sich durch Signaturen in Commits für das gemeinsame Repository und durch Spitznamen in Bug-Trackern. Ich bin nicht zu schlau, um in / ++ für verschiedene Betriebssysteme zu programmieren, und deshalb programmiere ich in PHP für Magento .


Um auf das Thema des Artikels zurückzukommen, kann ich sagen, dass der Namespace eine der sehr wichtigen Säulen ist, auf denen das Schreiben komplexer Webanwendungen auf einer Gruppe von Entwicklern basiert, die sich nicht auskennen.


In diesem Text meine ich mit Namespace Namespace aus Sicht von PHP , nicht Namespace aus Sicht von python :


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

Zum ersten Mal stieß ich beim Erlernen von Java auf einen Namespace, als ich versuchte, das Geheimnis der " Paket " -Richtlinie zu verstehen:


 package com.sun.source.util; 

Der Zweck dieser Richtlinie war nicht klar und was genau darin angegeben werden sollte, wenn eine Zeile angegeben werden konnte. Die Empfehlung der Autoren der Sprache, als Teil des Namens des Pakets zu verwenden, das auf Ihrer (in Ihrem Unternehmen) Domain registriert ist, sah etwas extravagant aus. Jetzt hat jeder, jeder, jeder seine eigene Domain, und eine solche Empfehlung ist nicht sehr peinlich, und vor 15 bis 20 Jahren habe ich sehr darüber nachgedacht, welche Domain als Name für mein erstes Paket verwendet werden soll und welche Auswirkungen dies in Zukunft haben könnte. Erst später, als ich Anwendungen mit maven , wusste ich die Einsicht dieser Empfehlung zu schätzen.


Abhängigkeitsmanager


Die Abhängigkeitsmanager haben mir geholfen, die Bedeutung des Namespace zu verstehen. Wenn Ihr Code Code von Drittanbietern verwendet, der von anderen Paketen abhängt, die von Drittanbietern abhängen, ist es sehr schwierig, die Reihenfolge in einem solchen Speicherauszug aufrechtzuerhalten. Gerade aufgrund der Back-Domain- Regel zum Benennen von Paketen in einem Haufen von JARs, die in einem Verzeichnis zusammengefasst sind (z. B. in WEB-INF/lib ), ist die Navigation jedoch einfach genug:


Bild


Vergleiche mit npm ( JavaScript ):


Bild


In Java Entwickler den " Back-Domain " -Namen von Paketen (aufgrund von Modulen) ziemlich weit verbreitet, in JS jedoch nicht. In Java Sie daher unabhängig voneinander eine große Anzahl konfliktfreier Pakete (Module) erstellen, ohne deren Namen explizit als unabhängige Entwicklungsgruppen zu vereinbaren. In JS müssen Sie die npm-Registrierung explizit verwenden. Ja, in Java ist die globale Domänenregistrierung implizit an der Lösung von Konflikten beteiligt, aber jede Community, nicht nur Java Encoder, kann dieselbe Namensregel verwenden.


In PHP der composer Abhängigkeitsmanager eine zweistufige Verzeichnisstruktur: ./company/module :


Bild


Dies bietet einen gewissen Vorteil bei der Abhängigkeitsnavigation gegenüber der einstufigen Zuordnung.


Hier sind die Statistiken für die zentralen Paket-Repositorys für Java / JS / PHP :


https://mvnrepository.com/repos/central - 3 358 578 indizierte Gläser
https://www.npmjs.com/ - 872 459 Pakete
https://packagist.org/statistics - 207 560 Pakete (1.472.944 Versionen)


Für maven höchstwahrscheinlich alle Versionen der Module in der Statistik berücksichtigt, während die Module selbst in npm und composer berücksichtigt werden.


Wofür ist der Namespace?


Die Hauptantwort besteht darin, Konflikte zwischen verschiedenen Codeelementen (Konstanten, Funktionen, Klassen, ...) zu vermeiden, die denselben Namen haben, sich jedoch in verschiedenen Modulen befinden. Python- Namespaces bewältigen dies erfolgreich. Aber ich würde hier immer noch den "Namespace" in Anführungszeichen setzen, weil im Wesentlichen ist es näher am Umfang .


Der Namespace gemäß den Versionen Java ( package ) und PHP ( namespace ) ermöglicht es zunächst, ein bestimmtes Codeelement in der Aggregat-Community eindeutig zu adressieren. Und dies ist eine Eigenschaft des Namespace (logische Gruppierung), die es ermöglicht, komplexere Softwaresysteme von weniger verbundenen Entwicklergruppen zu erstellen.


Adressierung von Softwareelementen


In PHP die Klasse \Doctrine\DBAL\Schema\Column eindeutig angesprochen, unabhängig davon, wie der Quellcode mit dem Projekt verbunden ist. Die IDE kann diese Adresse leicht bilden. In PhpStorm geschieht dies folgendermaßen (Rechtsklick auf ein Codeelement):


Bild


Der gleiche PhpStorm geht verloren, wenn Sie eine ähnliche Technik auf den JS Code anwenden (wo kein Namespace vorhanden ist). Versuchen wir, die Adresse für den Link zur JS query zu bilden:


Bild


Die Ausgabe ist module.query , was nicht informativ genug ist.


Um die query in der Dokumentation (Korrespondenz, Bug-Tracker usw.) zu adressieren, müssen Sie auf eine bestimmte Codezeile in der Datei verweisen:


Bild


Ergebnis: ./node_modules/express/lib/middleware/query.js:25


Wenn wir die Anzahl der Zeilen in einer Datei ändern oder eine Datei verschieben / umbenennen, haben wir in der Dokumentation natürlich eine veraltete Adresse des für uns interessanten Programmelements.


Die Verwendung des Namespace ermöglicht es daher, dass Links zu verschiedenen Elementen des Projektcodes viel länger relevant bleiben als Links zu einer Zeile in einer Datei.


Erkennen widersprüchlicher Codeversionen


Moderne komplexe Anwendungen können nicht ohne Abhängigkeitsmanager ( maven , composer , npm , ...) entwickelt werden. Gleichzeitig ziehen unsere Abhängigkeiten ihre Abhängigkeiten, die ihre eigenen ziehen usw., was zu Versionskonflikten für dasselbe Paket führen kann, die durch verschiedene Abhängigkeiten gezogen werden ( jar hell ).


In JS dies aufgrund des Fehlens von Namespace'ov nicht auf. Ich selbst bin auf eine Situation Magento bei der Installation zusätzlicher Module in Magento Anzahl der verschiedenen Versionen der von ihnen geladenen jQuery Bibliothek 5-6 überschritten hat. Ein solches Verhalten gibt den Entwicklern einerseits mehr Freiheit, andererseits stellt mehr Freiheit höhere Anforderungen an die Qualifikation. Nun, die Suche nach Fehlern in einer solchen Nudel von Abhängigkeiten mit mehreren Versionen - Qualifikationen sind ein oder zwei Ordnungen höher als Qualifikationen, um genau diese Fehler zu erzeugen.


Die Verwendung des Namespace in PHP erleichtert das Erkennen solcher Konflikte auf IDE-Ebene (z. B. habe ich eine zweite Datei mit einem Duplikat der darin enthaltenen Klasse erstellt):


Bild


Somit wird die Aufgabe, doppelte Codeelemente in einem Projekt zu erkennen, ziemlich einfach zu erledigen.


Code-Start


Die Funktion spl_autoload_register in PHP ermöglicht es dem Entwickler, sich nicht genau darum zu spl_autoload_register , wo sich die Dateien mit den Quellen seiner Klassen befinden. In jedem Projekt können Sie diese Funktion überschreiben und Ihren eigenen Algorithmus zum Laden von Skripten nach Klassennamen implementieren. Ohne die Verwendung eines Namespace mussten ziemlich lockige Namen für Klassen geschrieben werden, um deren Eindeutigkeit innerhalb eines komplexen Projekts sicherzustellen (insbesondere unter Berücksichtigung von Bibliotheken von Drittanbietern). In Zend1 abstrakte Adapter für die Arbeit mit der Datenbank wie folgt definiert:


 abstract class Zend_Db_Adapter_Abstract {} 

Um die Eindeutigkeit sicherzustellen, war es im Wesentlichen erforderlich, dem Klassennamen einen Namespace hinzuzufügen. Wenn Sie solche Klassennamen im Code verwenden, müssen Sie Ihre Augen natürlich weiter entlang der Linien bewegen.


In Zend2 , wo bereits Namespaces verwendet werden, sieht eine ähnliche Klassendefinition folgendermaßen aus:


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

Der Code wird schließlich lesbarer, aber das wichtigste Ergebnis der Verwendung des Namespace ist die Möglichkeit, die Funktionalität des Klassenladeprogramms mit der Bindung der logischen Hierarchie von Klassen an die Dateistruktur zu vereinheitlichen. Hier ist ein Auszug aus der Datei ./vendor/composer/autoload_namespaces.php , die composer in PHP damit der Loader ./vendor/autoload.php funktioniert:


 <?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'), ... 

Es ist ersichtlich, dass sich die Quellcodes in verschiedenen Bibliotheken auf unterschiedliche Weise befinden können (unterschiedliche Intra-Modul-Strukturen), und composer beim Erstellen des Projekts eine Karte zum Überlagern der logischen Hierarchie von Klassen im Dateisystem. Und Namespaces spielen bei dieser Überlagerung eine wichtige Rolle.


Um diese Rolle zu bewerten, reicht es aus, zu versuchen, ein npm Modul in mehrere kleinere Module aufzuteilen und Ihr Projekt neu zu erstellen, um zwei neue Module anstelle eines großen zu verwenden. Übrigens werden das Vorhandensein von Klassen in ES6 und das Fehlen eines Namespace im Sinne einer logischen Gruppierung von Code wahrscheinlich dazu führen, dass Namen ähnlich wie in Zend1 ( Module_Path_To_Class ) in großen ES6 Projekten Module_Path_To_Class werden.


IoC


Die Kennung von Objekten in IoC-Containern ist eine Zeichenfolge (zumindest in PHP ). In einfachen Beispielen sind Bezeichner wie dbAdapter , serviceB , serviceB usw. durchaus akzeptabel. Je größer das Projekt ist, desto schwieriger ist es searchFilterList wo das Objekt mit dem Bezeichner erstellt wird, z. B. searchFilterList und wo es verwendet wird. Der logische Ausweg besteht darin, Klassennamen als Bezeichner für Objekte zu verwenden. In diesem Fall wird die Logik zum Erstellen von Objekten durch den Container vorhersehbar, und der Quellcode und die Verwendungsorte werden elementar von der IDE bestimmt. Mit dem Namespace können Sie alle Projektklassen in einer logischen Struktur organisieren und beim Erstellen von Objekten mit einem Container die entsprechenden Pfade verwenden.


Zusammenfassung


In Anbetracht des oben Gesagten glaube ich, dass Programmiersprachen, die Nativräume verwenden, um Quellcode mithilfe der logischen Gruppierung ihrer Elemente zu strukturieren, die Erstellung komplexerer Anwendungen mit geringeren Kosten ermöglichen als Sprachen ohne logische Gruppierung. Dementsprechend kann die maximale Komplexität von Anwendungen, die in Java / PHP / C++ / ... erstellt werden können, nicht von Entwicklern mit denselben Qualifikationen in JavaScript / Python / C / .... erreicht werden.

Source: https://habr.com/ru/post/de434968/


All Articles