Is it possible to define a separate PSR-0/4 path for classes/interfaces that can only be loaded by the package itself (not other packages that include it)?
The idea being it would stop other packages from mistakenly using classes that should be private to the package.
I realise that they can always include the file manually and the class loader is global. The goal is not to prevent them from using the class, but rather make it clear that they shouldn't be accessing it directly now or if the API of the package changes.
Use case:
Let say there is a Person class in the package (already released and used). When a new version of the package arrives we no longer want them to invoke new Person, but instead use a PersonFactory (as it has to setup some other stuff with the person that the caller does not need to worry about).
Yes, you could document this in the change log. However an IDE and static analysers would not be able to report on this. The bug would only be discovered when the improperly initialised Person is given to a provider and the program crashes or throws an exception at runtime.
Based on Alexander's response, this seems the most reasonable:
https://repl.it/repls/GrowlingInconsequentialFanworms
I can't see how this would be possible, because the autoloader loads them into their defined namespaces on their first usage. Once in a namespace, anything can use it by accessing that namespace.
PHP namespace to not have any way of limiting what other namespaces can access them, so your answer is probably no.
What you could do though is put your private classes in a namespace that tells developers they are private:
use yourpackage\private\SomeClass;
It won't stop them, but it could make it clear they should not do that.
I don't think it's possible. spl_autoload_register() takes only $class as argument. You can't register autoload only for a part of application. Moreover there is no way to know which class invokes or creates object of the other classes. Even if you wrote your own autoloader you won't get all information that you need.
If you look for securing your code look at PHP extensions.
Am not sure if this is what you talking about but the php keywords private and protected should help a bit when the classes and interfaces are in a namespace
Related
I have not installed or tinkered with Zephir yet.
Because before I do, I'd like to know whether it is possible to define PHP classes inside a Zephir extension that can only be instantiated by the extension itself but not in userland.
Sort of a friend or protected/private class perhaps, or maybe a class defined outside of the extension's namespace, or something similar. Preferably not an anonymous class, though.
I could have sworn some native PHP extensions have similar classes (not able to be instantiated in userland) as well, but it just so happens I can't find any example right now. Perhaps I have simply imagined this.
In Symfony 2, all requests are getting routed through app_dev.php (or app.php).
The first few lines look like:
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;
...
In theory, I get that this just imports the specified namespace (or class) to the current scope. What I don't understand is how PHP maps this to a file. For example, the Debug class is located in:
vendor/symfony/symfony/src/Symfony/Component/Debug/Debug.php
How does PHP know to look in vendor/symfony/symfony/src/?
I'm probably misunderstanding what is happening, but any clarification would be appreciated.
Knowing which file a class lives in isn't the job of the language, it's the job of the autoloader.
All the use keyword does is this instance is create an alias:
use Symfony\Component\HttpFoundation\Request;
This is saying in the following script, when I refer to Request I really mean Symfony\Component\HttpFoundation\Request. If I use Request object in some way (by either creating an instance or calling a static method on it) then the autoloader will go and try to load the file that class is defined in if it hasn't been loaded already.
The inner workings of the autoloader, though, is different from project to project. There has been a move to standardize autoloader behavior à la PSR-4, but there's nothing in the language saying that you have to adhere to that standard. You could, for instance, have a scheme where all class files reside in a single directory and your autoloader just loads all classes from there, regardless of what namespace they're in.
That scheme would suffer from the fact that you could only have a single class of every name, but there's nothing stopping you from doing it that way.
To answer your question: "How does it know that "Symfony\Component\Debug\Debug" is a valid namespace?"
It doesn't, because it's not actually going out and trying to load that class at this point. If in any random PHP script you put something like this at the top:
use \Non\Existant\ObjectClass;
But don't ever actually use ObjectClass anywhere, you will get no errors. If you try to say new ObjectClass, though, you will get a class not found error.
Simplistically speaking, you have to load all the files beforehand into memory for PHP. PHP does not inherently have any standards to where files are located, the rules for loading files has to be done by your code.
When PHP attempts to load a file, it will check its memory if the class definition exists, if not it will attempt to autoload the file that may contain your class definition; see PHP: Autoloading Classes and spl_autoload_register
Some common autoloading strategies have been defined by the PHP Framework Interop Group:
PSR-0 (Autoloading standard)
PSR-4 (Improved Autoloading standard)
In this case, autoloading is done by Composer, all you need to do is include vendor/autoload.php in any of your scripts and vendor code downloaded via composer can be autoloaded. You can manually add classes into the composer autoloader as well. See: Composer Autoloading
I think this cannot be done do to the fact the PHP is a stateless language. But I will ask anyway...
I've created a home-grown MVC framework. The classes are all namespaced. On initial load I instantiate my custom Autoload class. A method of this class scans registered class directories (stored in the application config) and creates an array of fully qualified class names to paths. The array is stored as a protected member of this class. This member array is used by the spl_autoload() implementation. The Autoloader object is cached and reused on each http request.
This is fine and well. However, it irks me that every time an http request comes in to the domain my bootstrap routine has to register the autoload method to the __autoload stack. I would love to register it once and leave it alone.
I think the closest you can get to this would be opcode caching, where the parsing is done and machine language is built. Beyond that, you're right in that being a stateless language means it has to be built every time. I've never delved into it myself (so I'm not sure it would answer your question), but there is also pre-compiled PHP.
I haven't been able to find a strait answer to this question yet elsewhere online and was wondering how exactly composer autoloading worked.
When I autoload a class using PSR-0 or classmap what is actually happening behind the scenes? Is it just calling include(or some include variant) on the the specified file in the specified path. Is it actually skimming the file for class definitions and constructing its own file to include? Is it doing something that isn't analogous to a file include?
Thanks in advance!
A PSR-0 autoloader is simply a function attached to the global PHP process with spl_autoload_register(). That registered function is called whenever PHP needs to instantiate a class that isn't yet known, so this is the last moment to make the classes code known before PHP fails.
And the implementation of that autoloading can be either pretty sophisticated, or pretty simple, but in every case it will use either include() or require() (possibly with _once, but this is not really needed) to make the class code known to PHP. You could also implement a call to eval() to dynamically add some code that declares the class needed, but this would just be for academic used - I haven't seen it being used in real cases.
The same applies to the classmap loading. The classmap array contains names of classes as keys, and the filename of the containing file as value. This is for cases where there is no PSR-0-compatible ruleset mapping between class name and file path.
If you want more details of how Composer does the autoloading, you should have a look at the generated files inside vendor/composer. Basic knowledge about how PHP autoloading works in general would help understand what happens there.
Behind the scenes composer use spl_autoload_register to register an autoloader function which include your class.
The registered function follows a standardized namespace/path resolution algorithm (basically consider all "\" or "_" in your class name as path separators from a specified base directory) to find the php file to include.
Also, when you run composer install it create a cached index of relation between paths and namespace to speed up the path resolution.
You can dig in the Github repository and see it for yourself.
What solution would you recommend for including files in a PHP project?
There aren't manual calls of require/include functions - everything loads through autoload functions
Package importing, when needed.
Here is the package importing API:
import('util.html.HTMLParser');
import('template.arras.*');
In this function declaration you can explode the string with dots (package hierarchy delimeter), looping through files in particular package (folder) to include just one of them or all of them if the asterisk symbol is found at the end of the string, e.g. ('template.arras.*').
One of the benefits I can see in package importing method, is that it can force you to use better object decomposition and class grouping.
One of the drawbacks I can see in autoload method - is that autoload function can become very big and not very obvious/readable.
What do you think about it?
What benefits/drawbacks can you name in each of this methods?
How can I find the best solution for the project?
How can I know if there will be any performance problems if package management is used?
I use __autoload() extensively. The autload function that we use in our application has a few tweaks for backwards compatibility of older classes, but we generally follow a convention when creating new classes that allow the autoload() to work fairly seemlessly:
Consistent Class Naming: each class in its own file, each class is named with camel-case separated by an underscore. This maps to the class path. For example, Some_CoolClass maps to our class directory then 'Some/CoolClass.class.php'. I think some frameworks use this convention.
Explicitly Require External Classes: since we don't have control over the naming of any external libraries that we use, we load them using PHP's require_once() function.
The import method is an improvement but still loads up more than needed.
Either by using the asterisk or loading them up in the beginning of the script (because importing before every "new Classname" will become cumbersome)
I'm a fan of __autoload() or the even better spl_autoload_register()
Because it will include only the classes you're using and the extra benefit of not caring where the class is located. If your colleges moves a file to another directory you are not effected.
The downside is that it need additional logic
to make it work properly with directories.
I use require_once("../path-to-auto-load-script.php.inc") with auto load
I have a standard naming convention for all classes and inc files which makes it easier to programaticaly determine what class name is currently being requested.
for example, all classes have a certain extension like inc.php (so I know that they'll be in the /cls directory)
and
all inc files start with .ht (so they'll be in the /inc directory)
auto load accepts one parameter: className, which I then use to determine where the file is actually located. looping once I know what my target directory is, each time adding "../" to account for sub sub pages, (which seemed to break auto load for me) and finally require_once'ing the actual code file once found.
I strongly suggest doing the following instead:
Throw all your classes into a static array, className => filepath/classFile. The auto load function can use that to load classes.
This ensures that you always load the minimum amount of files. This also means you avoid completely silly class names, and parsing of said names.
If it's slow, you can throw on some accelerator, and that will gain you a whole lot more, if it still is slow, you can run things through a 'compile' process, where often used files are just dumped into common files, and the autoload references can be updated to point to the correct place.
If you start running into issues where your autoloading is too slow, which I find hard to believe, you can split that up according to packages, and have multiple autoloading functions, this way only subsets of the array are required, this works best if your packages are defined around modules of your software (login, admin, email, ...)
I'm not a fan of __autoload(). In a lot of libraries (some PEAR libraries, for instance), developersuse class_exists() without passing in the relatively new second parameter. Any legacy code you have could also have this issue. This can cause warnings and errors if you have an __autoload() defined.
If your libraries are clear though, and you don't have legacy code to deal with, it's a fantastic tool. I sometimes wish PHP had been a little smarter about how they managed the behavior of class_exists(), because I think the problem is with that functionality rather than __autoload().
Rolling your own packaging system is probably a bad idea. I would suggest that you go with explicit manual includes, or with autoload (or a combination for that matter).