--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/qT7mEy0RIuI/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
- Autoloader implementations MUST allow each namespace prefix to be mapped to multiple directories.
-- pmj
$loader = new ClassLoader;
$loader->add('Foo\Bar', '/path/too/Foo/Bar');
$loader->findFile('Foo\Bar\Baz');
Results in this output:
/path/too/Foo/Bar/Baz.php
So we need to do one of the following:
- modify PSR-0 to say that complying with this proposal (if accepted) is a sufficient alternative
- modify PSR-1 to say "comply with PSR-0 +++or PSR-N+++"
- modify this proposal to state that complying with it is sufficient to meet the requirement of complying with PSR-0 for the purposes of PSR-1
-- pmj
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/qT7mEy0RIuI/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.
-- pmj
Then we would have to create PSR-6 to modify PSR-2 because it references PSR-1. Yay for cascading references!
No, I think Evert's idea of specifying in the proposal that the PSR-1 requirement to follow PSR-0 is amended to include the new proposal (provided it passes) is reasonable.
Hey Hari - What does that show? Not following.
namespace SebastianBergmann\PSON{
}or may be I am wrong also.And I love PSR-0, for the consistency and I fear people using 2 different PSR and later causing
trouble.Also I am in a dialama wondering whether this is a way to go or not. Anyway for I am not a voting member
I will wait what the outcome is.Also at-times I feel your point is correct that we are trying to solve the module problem for CMS and
not the library.I cannot think more for the current time, but I will hear what others say and how this goes well.
Greetings all,
N.b.: If this proposal is adopted, PSR-1 MUST be be amended so that the requirement to follow PSR-0 becomes a requirement to follow either PSR-0 or this proposal.
Let the beatings commence!
* * *
Package-Oriented Autoloader
===========================
Introduction
------------
The PSR-0 class naming and autoloading standard rose out of the broad acceptance of the Horde/PEAR convention under the constraints of PHP 5.2 and previous. With that convention, the tendency was to put all PHP source classes in a single main directory, using underscores in the class name to indicate pseudo-namespaces.
With the release of PHP 5.3 and the availability of namespaces proper, PSR-0 was introduced to allow both the old Horde/PEAR underscore mode *and* the use of the new namespace notation. Underscores were still allowed in the class name to ease transition from the older namespace naming to the newer naming, and thereby to encourage wider adoption.
However, with the recent proliferation of packages, modules, and bundles in PHP, we note that conforming to the PSR-0 standard leads to deeper empty directory structures in distributions, like the following:
Foo_Bar_Package/
src/
Foo/
Bar/
Baz.php # Foo\Bar\Baz
tests/
Foo/
Bar/
BazTest.php # Foo\Bar\BazTest
The behavior has been noted as problematic:
- <https://igor.io/2013/01/23/autoload-insanity.html>
- <https://groups.google.com/d/msg/php-fig/-BPdegzme_Y/ZVR_4gVMoIkJ>
This proposal seeks to provide an *alternative to* (not a *replacement for*) PSR-0 that allows for a structure that makes the directory structures less deep, like the following:
Foo_Bar_Package/
src/
Baz.php # Foo\Bar\Baz
tests/
BazTest.php # Foo\Bar\BazTest
Additionally, since the use of underscores in class names was to represent pseudo-namespaces in PHP 4 to PHP 5.2.x, their use when namespaces proper are available is no longer necessary. This removes possible conflicts between `Foo\Bar` and `Foo_Bar`.
Rules
-----
(The term "class" below refers to classes, interfaces, and traits.)
- Fully-qualified class names MUST begin with a top-level namespace name, which MUST be followed by zero or more sub-namespace names, and MUST end in a class name.
- Class files MUST contain only one class definition.
- Autoloader implementations MUST map a namespace prefix to a directory.
- Autoloader implementations MUST allow each namespace prefix to be mapped to multiple directories.
- Autoloader implementations MUST map the non-namespace-prefix portion of the fully-qualified class name to a sub-path by replacing namespace separators with directory separators, and MUST suffix the result with `.php`.
- Autoloader implementations MUST search for class files among their registered namespace prefixes in a depth-first fashion.
- Autoloader implementations MUST search the paths for a registered namespace in the order those paths were registered.
Narrative
---------
Given the below example implementation, and a `Foo\Bar` package of classes, one would register the path to "source" files and "unit test" files for the namespace prefix like so:
// instantiate the loader
$loader = new PackageOrientedLoader;
// register the source file paths for the namespace prefix
$loader->addNamespacePath(
'Foo\Bar',
'/path/to/Foo.Bar/src'
);
// register the unit test paths for the namespace prefix
$loader->addNamespacePath(
'Foo\Bar',
'/path/to/Foo.Bar/tests'
);
Given a package in a "sub-namespace" of `Foo\Bar\Baz\Dib`, one would register the "sub-package" like so:
$loader->addNamespacePath(
'Foo\Bar\Baz\Dib',
'/path/to/Foo.Bar.Baz.Dib/src'
);
When the autoloader calls `load()` for a fully-qualified class name of `Foo\Bar\Baz\Dib\Zim\Gir`, the implementation will search the registered paths in this order:
- first, for `/path/to/Foo.Bar.Baz.Dib/src/Zim/Gir.php`;
- then, for `/path/to/Foo.Bar/src/Baz/Dib/Zim/Gir.php`;
- last, for `/path/to/Foo.Bar/test/Baz/Dib/Zim/Gir.php`;
Note that the longest registered namespace prefix that matches the fully-qualified class name is searched first, and the shortest is searched second. When a registered namespace prefix has multiple paths, the paths are searched in the order they were registered.
Example Implementation
----------------------
The following is one possible implementation of the rules described above.
<?php
/**
* An example implementation for a package-oriented autoloader.
*/
class PackageOrientedAutoloader
{
/**
*
* An array where the key is a namespace prefix, and the value is a
* sequential array of directories for classes in that namespace.
*
* @var array
*
*/
protected $paths = array();
/**
*
* Adds a path for a namespace prefix.
*
* @param string $ns The namespace prefix.
*
* @param string $path The directory containing classes in that
* namespace.
*
* @return void
*
*/
public function addNamespacePath($ns, $path)
{
$path = rtrim($path, DIRECTORY_SEPARATOR);
$this->paths[$ns][] = $path;
}
/**
*
* Loads the class file for a fully qualified class name.
*
* @param string $fqcn The fully-qualified class name.
*
*/
public function load($fqcn)
{
// a partial file name for the class
$name = '';
// go through the parts of the fully-qualifed class name
$parts = explode('\\', $fqcn);
while ($parts) {
// take the last element off the fully-qualified class name
// and add to the partial file name. always have a leading
// directory separator here.
$name = $name . DIRECTORY_SEPARATOR . array_pop($parts);
// the remaining parts indicate the registered namespace
$ns = implode('\\', $parts);
// is the namespace registered?
if (! isset($this->paths[$ns])) {
// no, continue the loop
continue;
}
// the namespace is registered. look through its paths.
foreach ($this->paths[$ns] as $path) {
// create a complete file name from the path
// and partial name
$file = $path . $name . '.php';
// can we read the file from the filesystem?
if ($this->readFile($file)) {
// yes, we're done
return true;
}
}
}
// never found a file for the class
return false;
}
/**
*
* Uses `require` to read a file from the filesystem.
*
* @param string $file
*
* @return bool True if the file gets read; false if it does not.
*/
protected function readFile($file)
{
if (! is_readable($file)) {
return false;
}
require $file;
return true;
}
}
* * *
-- pmj
In any case, this discussion will hijack the rest of Paul's proposal so I'd suggest separating it into another thread. I'll start one if nobody else does shortly...
If, for example, Symfony goes with PSR-1+4 but Doctrine sticks with PSR-1+0, but both state they are PSR-1 compliant is that going to cause an interoperability issue?
How will this impact Composer?
What if I want to bring in packages that uses the two different standards?
Does the end result require a project to follow one or both autoloading approaches?
Greetings all,
N.b.: If this proposal is adopted, PSR-1 MUST be be amended so that the requirement to follow PSR-0 becomes a requirement to follow either PSR-0 or this proposal.
Let the beatings commence!
-- pmj
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
Why even formalize this? You can just use the "classmap" autoloading for a Composer package that doesn't follow PSR-0 and be done with it.
Then they'll be fine. Because PSR-0 (or PSR-X) compliance starts at the package specific defined folder (not the root vendor/ folder) you could easily mix and match PSR-0 and PSR-X in the exact same way you can mix in old PHP 5.2 classmap'ed stuff already.
... (I'm working on the principle that if Don is happy, I'm happy), ...
Amy:How will this impact Composer?It wont, other than the Composer team will need to support a new option in the composer.json:"autoload": {"psr-X": {}},What if I want to bring in packages that uses the two different standards?Then they'll be fine. Because PSR-0 (or PSR-X) compliance starts at the package specific defined folder (not the root vendor/ folder) you could easily mix and match PSR-0 and PSR-X in the exact same way you can mix in old PHP 5.2 classmap'ed stuff already.
Though, in doing that, you most certainly set a precedent for another PSR being amended to support ^%^%^ OR #@#@#@ indentation :PRegards,Andrew Eddie
--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/qT7mEy0RIuI/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/php-fig/-/hZ75AuUkqY4J.
2. My hope that we could avoid another standard and address the
problem by adapting our practices: the folder structure
*recommendations* and seeing if Composer would consider allow those
first two nodes following vendor to be mixed case. Combined, those two
changes in practice, alone, would allow install paths like this (even
this new standard won't get that short of install paths):
vendor/Molajo/FieldHandler/Type/Alpha.php
3. My belief that part of the problem that the proposal attempts to
solve is outside of the scope of PSR-0 and FIG in that it addresses
files and folders that are NOT shared between projects, but rather
specific to that particular project's distribution. I love it that a
shared autoloader is being developed to help with that problem and I
shared in the other thread with Larry how I dealt with that issue,
too. But, it's my opinion that collaboration can be done without
impact to the standard.
4. Tabs and spaces. Brackets on Lines. There is a never ending list of
let's do it this way that follows once the finger is pulled out of the
dyke on changing standards.
Regarding Beau Simensen's comment:
>> - Autoloader implementations MUST allow each namespace prefix to be mapped to multiple directories.
>
> Does this need to be specified? I can see specialized PSR-X autoloader implementations that will have no need for supporting multiple directories being mapped. Would it make more sense to either drop this or change MUST to MAY?
I think it's necessary to allow it, so that users who expect to be able to map multiples using one implementation, can still do so in other implementations.
Please find the new proposal below, and let the beatings re-commence.
...
- Autoloader implementations MUST allow each namespace prefix to be mapped to multiple directories.
- Autoloader implementations MUST allow directory mappings to be appended or prepended to the existing directory mappings for that namespace prefix.
spl_autoload_register(function ($className) {$prefix = 'Dflydev\\MyFancyLib\\';$basePath = __DIR__.'/src/';if (strncmp($prefix, $className, strlen($prefix)) === 0) {$path = $basePath.str_replace('\\', '/', substr($className, strlen($prefix))).'.php';if (file_exists($path)) {require $path;return true;}}return false;});
Foo_Bar_Package/ src/ Baz.php # Foo\Bar\Baz tests/ BazTest.php # Foo\Bar\BazTest Additionally, since the use of underscores in class names was to represent pseudo-namespaces in PHP 4 to PHP 5.2.x, their use when namespaces proper are available is no longer necessary. This removes possible conflicts between `Foo\Bar` and `Foo_Bar`. 2. Specification ---------------- (The term "class" refers to classes, interfaces, and traits.) - Fully-qualified class names MUST begin with a top-level namespace name, which MUST be followed by zero or more sub-namespace names, and MUST end in a class name. - Class files MUST contain only one class definition. - Autoloader implementations MUST map a namespace prefix to a directory.
DIRECTORY_SEPARATOR
when
loading from the file system."- Autoloader implementations MUST allow each namespace prefix to be mapped to multiple directories.
- Autoloader implementations MUST allow directory mappings to be appended or prepended to the existing directory mappings for that namespace prefix. - Autoloader implementations MUST map the non-namespace-prefix portion of the fully-qualified class name to a sub-path by replacing namespace separators with directory separators, and MUST suffix the result with `.php`. - Autoloader implementations MUST search for class files among their registered namespace prefixes in a depth-first fashion. - [PSR-1][] MUST be amended to grant this PSR equal standing with [PSR-0][].
3. Narrative ------------ Given the below example implementation, and a `Foo\Bar` package of classes, one would register the path to "source" files and "unit test" files for the namespace prefix like so: // instantiate the loader $loader = new PackageOrientedLoader; // register the source file paths for the namespace prefix $loader->addNamespacePath( 'Foo\Bar', '/path/to/Foo.Bar/src' ); // register the unit test paths for the namespace prefix $loader->addNamespacePath( 'Foo\Bar', '/path/to/Foo.Bar/tests' ); Given a package in a "sub-namespace" of `Foo\Bar\Baz\Dib`, one would register the "sub-package" like so: $loader->addNamespacePath( 'Foo\Bar\Baz\Dib', '/path/to/Foo.Bar.Baz.Dib/src' );
When the autoloader calls `load()` for a fully-qualified class name of `Foo\Bar\Baz\Dib\Zim\Gir`, the implementation will search the registered paths in this order: - first, for `/path/to/Foo.Bar.Baz.Dib/src/Zim/Gir.php`; - then, for `/path/to/Foo.Bar/src/Baz/Dib/Zim/Gir.php`; - last, for `/path/to/Foo.Bar/test/Baz/Dib/Zim/Gir.php`; Note that the longest registered namespace prefix that matches the fully-qualified class name is searched first, and the shortest is searched second.
Would this summary be a correct understanding of this PSR?
is it worth providing an interface for registering multiple mappings in one go?
Also, does the namespace being registered need to be anything more than "\", i.e. no namespace? It sounds like this proposal could be used in legacy code that does not have any namespaces at all, so long as the PHP scripts contain only one class and the scripts are named after the class.
I guess taking that to its extreme, every single class within a package could have its entire namespace mapped to a physical location, and then the argument we have heard in other places that mapping namespaces directly to physical paths is restrictive, can be completely bypassed.
is it worth providing an interface for registering multiple mappings in one go?This is a feature that would make sense for many PSR-X autoloaders to implement but there is no actual interface defined in this PSR. As with PSR-0, it only defines the rules by which mapping a fully qualified class name to a filesystem path should happen.
Also, does the namespace being registered need to be anything more than "\", i.e. no namespace? It sounds like this proposal could be used in legacy code that does not have any namespaces at all, so long as the PHP scripts contain only one class and the scripts are named after the class.This proposal requires at least one level of namespace, \<Vendor>. This is in order to ensure that there are no naming collisions between packages. For example, if Zend, Symfony, and Acme each have a Cache class, by ensuring the fully qualified class name is \Zend\Cache, \Symfony\Cache, and \Acme\Cache, the classes will not clobber each other.
It would be easy to drop the requirement of the \<Vendor> namespace on the technical side of things but I think that the notion of requiring at least a vendor in the namespace something the group is not likely to change its mind on.As far as targeting legacy code, this proposal is pretty clear on its intention of actually removing support for pre-namespace legacy code that gave PSR-0 some trouble so I think changes that will make legacy code easier to deal with are going to be a hard sell. I think other arguments would need to be made for the case of dropping the \<Vendor> requirement.I guess taking that to its extreme, every single class within a package could have its entire namespace mapped to a physical location, and then the argument we have heard in other places that mapping namespaces directly to physical paths is restrictive, can be completely bypassed.It sounds like you are talking about mapping each individual class. The kind of flexibility that this proposal would allow for is letting you map Acme\Controllers => app/system/controllers and would result in the class Acme\Controllers\ZimController being found at app/system/controllers/ZimController.php and Acme\Controllers\GirController being found at app/system/controllers/GirController.php.
I believe there are four issues people tend to complain about related to the long install paths. Do you agree these are the four problems? Did I miss something? Is there a problem listed that isn't considered a problem?
i. Composer could be modified to use the name as it is entered in the Composer.json file. Then, those folders would be available for use with the PSR-0 namespace. The install path would then be:
vendor\Acme\Cache\Adapter.php
ii. Use lowercase values for namespace (ex. acme/cache instead of Acme/Cache). The install path would then be:
iii. PSR-X Simple don't include Acme\Cache in the repository structure and instruct the class loader to start the namespace at vendor\acme\cache. Thus, the install path would then be:
vendor\acme\cache\Adapter.php
2. Src Folder Repository Practice
Many use an approach of structuring the repository folder system using a high-level src/ folder. For those who use this approach, the namespace cannot begin until after the src folder.
Thus, the install path becomes:
vendor\acme\cache\src\Acme\Cache
iii. PSR-X does not directly address this. I am guessing the idea would be to not include the Acme/Cache in the folder structure, but continue with the Src folder, and if that is correct, it would have an install path like:
vendor\acme\cache\src\Adapter.php
3. Composer target-dir adds additional folders. ex. target-dir=more\folders results in:
vendor\acme\cache\more\folders\src\Acme\Cache
Possible solution: Don't use target-dir =)
4. Namespacing full distributions, not just packages Composer installs into the vendor folder.
Now, this is the one question that I see PSR-X addressing specifically that is not addressed above. The idea, as I understand it, would be that there is no reason to have the Acme folder to store source code that is not shared via packagist/composer. Just create your distribution folder structure, then instruct the class loader with how to load it.
But - my question is - does FIG need a PSR to address namespacing for code that is not shared?
There is confusion that will result from having two namespace standards from the same body for a relatively small population. If Composer cannot be adapted, why not change PSR-0? Those who are in compliance now will still be in compliance with PSR-0 using the rules under PSR-X so there is no backwards compat issues.
So, Paul, here are my questions for you -
1. Are the four problems I identified essentially the problems your proposal aims to resolve? (If so, good, we agree on the issues.)
2. Do you see the alternatives I listed above as impossible or not appropriate to solving the problem? (If so, fine, at least the ideas were considered.)
3. Why not just adapt PSR-0 instead of adding another namespacing standard? (Do you agree there are no backwards compatability issues? And can the group agree that change in our industry is unavoidable and nothing to be worried about? ;-) )
I do believe it's important to get moving one way or the other on this, no sense in holding projects back.
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/php-fig/-/iuvsAYuW9MgJ.
It matches my understanding perfectly. Thanks Larry.
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/php-fig/-/xeI6-q0bhcAJ.
<https://github.com/php-fig/fig-standards/blob/master/proposed/package-oriented-autoloader.md>
This PSR is intended as an alternative to, not a replacement for, PSR-0. It removes some legacy compatibility features that were built into PSR-0 (specifically how _ are handled) and it allows for classes to map to directory structures that are less artificially deep than PSR-0 required.
...
I think the Overview could be updated to be a bit more descriptive, especially if the example section is moved to the Narrative.
This PSR is intended as an alternative to, not a replacement for, PSR-0. It removes some legacy compatibility features that were built into PSR-0 (specifically how _ are handled) and it allows for classes to map to directory structures that are less artificially deep than PSR-0 required.
...
Let me try to simplify even further:
PSR-X: Same as PSR-0, but with the following additions:
1) Underscores in class names have no special meaning or processing.
2) You may optionally specify a point within the fully qualified name of a class where the directory mapping starts, rather than it always being at the start of the name. How you specify that is, I suppose, up to the implementation. (In composer.json it would probably be a property in the autoloader block.)
Exactly - PSR-0 fits into PSR-X. So, why not just amend the standard since everyone who is PSR-0 compliant would be PSR-X complaint.
On Tuesday, May 7, 2013 3:55:47 PM UTC+2, Amy Stephen wrote:
Exactly - PSR-0 fits into PSR-X. So, why not just amend the standard since everyone who is PSR-0 compliant would be PSR-X complaint.Amending PSR-0 in such a way is not really an option, and I believe this has been discussed quite a bit already. One long discussion took place on the PHP town hall podcast[0].
It introduces one of two cases.a) The new rules are mandatory, which means every existing PSR-0 implementation is no longer compliant until it adds support for the new stuff.
Not seeing the problem.
The following is an example of a hypothetical project-specific PSR-X compatible autoloader. It illustrates how afully-qualified class name should interact with a namespace prefix and a base directory in order to determine the location of the file containing the requested class, interface, or trait.
<?php // Given a PHP file named /path/to/project/example.php with the following // content: spl_autoload_register(function ($fqcn) { $namespacePrefix = 'Foo\Bar'; $baseDirectory = __DIR__.'/src/'; if (0 === strncmp($namespacePrefix, $fqcn, strlen($namespacePrefix))) { $nonNamespacePrefix = substr($fqcn, strlen($namespacePrefix)); $nonNamespaceFilename = str_replace('\\', '/', $nonNamespacePrefix).'.php'; $path = $baseDirectory.$nonNamespaceFilename; if (file_exists($path)) { require $path; return true; } } return false; }); // On calling the following line, the PSR-X compatible autolaoder registered // above would attempt to load the FQCN from /path/to/project/src/Dib/Zim.php new Foo\Bar\Dib\Zim;
This SHOULD NOT be seen as anything more than an example implementation of the PSR-X Specification. PSR-X class loaders MAY contain additional features and may differ in how they are implemented. As long as a class loader adheres to the rules set forth in the Specification they MUST be considered PSR-X compatible.
Is the underscore issue behind us, now? Rereading Paul's first post, sounds like since 5.2, maybe this approach is no longer needed? Are projects adapting? Or, is PSR-0 essentially needed for that purpose until those migrations have taken place?
Still trying to see why two namespace standards are needed.
Is this basically correct?PSR-X requires two things:1) A distinct high-level qualifier (ex. 'Aura', 'Drupal', 'Molajo');
Asked differently, would resolving this namespace: Foo\Bar\Adapter, as follows, be compliant?$loader->addNamespacePath(
'Foo\Bar',
'/path/to/Wherever/I/Want/To/Put/It/Adapter.php'
);
I also think it would be helpful to have Anthony, or others who struggled with PSR-0, to look at PSR-X and make sure they feel good about it. Hopefully, his concerns are addressed.
Is the underscore issue behind us, now? Rereading Paul's first post, sounds like since 5.2, maybe this approach is no longer needed? Are projects adapting? Or, is PSR-0 essentially needed for that purpose until those migrations have taken place?Yep, no need to keep supporting that. Hello PHP 5.3.
Still trying to see why two namespace standards are needed.Because PSR-0 is set in stone, and changing it would break things for current people. If we say "And boom, _ is gone" then that breaks things for everyone. Much confusion.
Is this basically correct?PSR-X requires two things:1) A distinct high-level qualifier (ex. 'Aura', 'Drupal', 'Molajo');Yep.
Are your concerns addressed?