Does PHP's use statement cause extra work when loading classes? - php

Code Sample 1
use Outline\Drawing;
$var = new Drawing();
Code Sample 2
$var = new Outline\Drawing();
Question:
Does PHP make hardware work harder (look up more files or do more processing) if I use code in sample 1? I am sure something gets done, even if it is at the level of some code that figures out which use line gets matched up with which class. I want to find out exactly what is happenning.
In short:
What does PHP do when working out the connection between the use of the use statement and a class it is supposed to be for?
Are PSR-0/PSR-4 autoloaders affected in the way they work when it comes to these two code samples?

What does PHP do when working out the connection between the use of the use statement and a class it is supposed to be for?
The use statement doesn't actually load the namespace/class into your file. It simply sets up a list of aliases to refer to the classes in that namespace.
When it encounters a class that hasn't yet been declared, it uses that list of aliases to try to fully qualify the class name (prefix replacement). If it can't find an alias for the class, it'll use the namespace of the current scope to qualify the class name.
Only when the class name is fully qualified, that php will try to autoload the class (calling the various autoloaders that might have been defined).
Are PSR-0/PSR-4 autoloaders affected in the way they work when it comes to these two code samples?
No, autoloaders are not affected in the way they work by the difference in your code samples because php will call the autoloaders exactly the same way with exactly the same parameters.

Related

Using spl_autoload_register without using include

I've seen a lot of threads here and in other forums that asked this a lot of times, but I still see using the include function of PHP in the answers?
how can I use this function, not using totally the include function?
Thank you
how can I use this function, not using totally the include function
You cannot totally not use include and that is not the point of using autoloader as you usually need to at least include the autoloader ;). That autoloader is the regular PHP code that is being called by PHP when unknown class use is attempted in the code. It is expected to include right file to make the class known, and the code continues as you'd explicitely include right file by hand in your code. So the main benefit shows up when your code uses classed (OOP) - you do not need to care if you included the class you are about to instantiate the object of or not. You just do new Foo() or call Something::methodName() and if all is set up right it will work.
The function spl_autoload_register is used to register a callback into the autoloader queue.
The PHP autoloader is a functionality of the PHP interpreter that, when a class is not defined, calls the functions registered in the queue, one by one, asking them to load the class, until the class becomes available. It the class is still not available after all the functions were invoked, the interpreter triggers a fatal error.
The autoloader doesn't perform any magic. It is the entire responsibility of the registered functions to make the class available. Most of them use the name and namespace of the missing class to figure out the path of the file that contains the declaration of the class and include it.
That's how the thing works. There are not many ways to produce a class in PHP and, for a reusable autoloader callback, the list starts and ends with include1 (include_once, require or require_once can be used as well but they don't make any difference in this case.)
The autoloader callback itself stays in separate file (for reusability) and usually that file also contains its registration as autoloader callback (the call to spl_autoload_register). All your code have to do is to include this file once in every file that is an entry point of your application.
All things being equal, your application needs to use include at least once and once is also the maximum required number of usages for it. The autoloader callback also uses include (probably also only once) but you don't write autoloader callbacks every day. If you wrote one and you wrote it well you can reuse it. Most people never wrote an autoloader callback and they will never write one.
Using Composer is easy and if you follow the PSR-4 rules of naming the files of your project, Composer can generate an autoloader for your project that knows how to load your classes (behind the scene it uses include, of course). All you have to do is to run composer init in the root directory of your project, run composer install and write include 'vendor/autoload.php'; in the file that represents the entry-point of your application. No other uses of include are required.
1 An autoloader callback is not required to include another file to make the class available. It can generate the code of the class on the fly and eval()-uate it, but the use cases of such approach are very limited. It is used by the testing suites f.e., to generate mock classes.

Hooking into function calls in php

A little background: At runtime I would like to be able to inspect the currently called functions javadoc-style documentation, to determine its formal (typed) declaration. This would allow runtime type checking (for simple and complex types) by means of reflection (at a cost) during debugging and testing, something that I would find immensely helpful.
So, in php I would like for a user defined function to get called whenever any other function is about to get called. That is, if a function foo() gets called, I would like to have my callHookHandler() function called immediately before.
One solution would be to implement __call() in all user defined classes, but that is both unwieldy and doesn't include support for functions defined outside classes, so I am looking for a better solution.
This sounds a bit of a fun one so I'm going to give answering it a try.
I hope this helps you. Let me know how it goes.
So, what you are asking can be done, and here's how:
For Functions:
Get all defined functions with $function = get_defined_functions().
Loop through the $functions['user'] key and inspect each one with the ReflectionFunction class. You'll need to get:
The comment using ->getDocComment()
The arguments using ->getParameters()
Do some magic (I'll let you figure out how to parse the comment using some regular extressions and match it up with the parameter list from the reflection. Don't forget optional parameters!)
Rename the function using runkit_function_rename
Generate code in a string that checks the parameters and calls the renamed function
Generate a parameter list as a string
Create a new function with runkit_function_add using the code you generated in step #5 and the parameter list from step #6.
For Classes:
Get a list of classes with $classes = get_declared_classes();
Loop through each one and inspect it with ReflectionObject and ->getMethods() to get the methods. Make sure that the class is not internal with ->isInternal() because we can't do anything about the internal classes.
In an inner loop... go through each method using the ReflectionMethod class. Get the arguments and PHPDoc/JavaDoc comments just like you did with normal functions.
Do the same thing you did with the functions only use runkit_method_add and runkit_method_rename instead.
Downsides:
You won't be able to do the checking on internal class methods and functions (which is fine because they won't have doc comments anyway).
This is a lot of work! I left a lot of parts up to your imagination to avoid this being the length of a short book.
Please send me this or open source it and let me know when you finish, I really want to use this myself. Contact info is on my website which is in my profile ;)
Alternatively:
You can use XDebug's function trace along with reflection then analyze the results after the fact so that you don't have to dynamically edit the code. If you want to write unit-test you could even automate it.
Hope type checking makes it into future versions of PHP and wait: https://wiki.php.net/rfc/typechecking
Notes:
This class reference has a potentially useful example of parsing docComments in the comments section of the page:
http://us.php.net/manual/en/class.reflectionmethod.php
References
get_defined_functions
get_declared_classes
ReflectionFunction
ReflectionObject
ReflectionMethod
runkit
Alternative way to hook into function call is to use a trick with namespaces: Intercepting Execution of System Functions in PHP
You can also use the Go! framework to define an aspect to intercept the execution of system functions automatically.

Load a class with a different name than the one passed to the autoloader as argument

basically, I have the following problem: I want to make use of PHP's new namespace features. Unfortunately, I'm running a PHP version (5.3.2) in which namespace-autoload-support for linux still seems buggy and does not work (PHP should be able to load the class file automatically by its namespace without having to use a custom autoloader, but that doesn't work).
What I want to achieve is to write an autoloader that I can simply remove as soon as the php's namespace features work correctly (there seems to be a speed advantage when not using a custom autoloader) with having to change as less code as possible afterwards.
So I have a call like this:
$filereader = new system\libraries\file\XML();
which gets passed correctly as the string "system\libraries\file\XML" to my autoload-function. I can load the corresponding file "system/libraries/file/XML.class.php". However, the class in there will be named
class XML { ... }
(or something different than "system\libraries\file\XML") and so have a different name than the one by which PHP will try to load it. So is there an easy way to load that class ("XML") which has a different name than the name which I pass to the autoloader function? Can I perhaps do something in the autoloader to achieve that behaviour? (I'm using spl_autoload_register).
I know that even if it worked out I would still not be able to use all features of namespacing, since a (simple) autoloader would not respect the "use namespace" directive and I would still have to use rather long names for loading a class. However, if I understood PHP's namespace-features correctly, I could leave the code as it is when I later switch to using native namespace support instead of my autoloader.
If what I try to do does not make sense at all in your opinion or if I misunderstood namespaces, please tell me (- I have not used PHP's namespace features yet).
I would load the file (which creates the XML class) and then alias the XML class to the properly namespaced system\libraries\file\XML class:
class_alias('XML', 'system\libraries\file\XML');
More generally:
class_alias(basename($class), $class));
Though I'm not quite sure whether class_alias can alias to namespaced classes...

Is there something like a macro in PHP? Or: How to make an own include function?

What I want to do is this:
When I write a class and the class instantiates another class, I want to import that class with an require_once. Just the way I do so in Objective-C. But instead of using plain require_once function and messing around with paths and string concatenation, I would prefer something like:
importClass('myclass');
but I'm afraid that it's impossible to write a function that will include code. If I would do that in the importClass() function, I would include the class code into the implementation block of the function, which of course is nonsense. So what options do I have here?
The cleanest way to do what you want looks to be to use the Autoloader
It's not impossible at all. You can write this function:
function importClass($class) {
require_once "$class.class.php";
}
The only caveat is that any global variables declared or used inside that file will now be local to importClass(). Class definitions however will be global.
I'm not sure what this really gives you however but you can certainly do it.
In my application I have a system base class which has a similar function. The import function takes a class name, looks in a couple of related directories and finds a matching name (I also did some stuff with extensions to libraries but you may not need that) and instantiates a class inside with the same name. Then it takes that new instance and sets it as an object in the system base class.
using autoload as other answers have suggested would probably work better in your situation but this is just another way to look at it.
You can accomplish something similar using a class autoloader. I would also make sure that your include_path is set properly and that you are using a directory structure that makes sense for your classes - it's generally a good practice to NOT depend on class autoloaders, and instead include classes based on their relative path to your include_path.
I'd highly recommend browsing through Zend Framework, particularly Zend_Loader, for a good (if not over-architected) implementation. Also notice that Zend Framework will work without an autoloader in place - each file calls require_once on its direct dependencies, using their nice, organized directory structure.

Is using namespaces to partition a project bad practice?

I have recently learnt about namespaces in PHP, and was wondering, would it be bad practice to do this?
<?php
namespace String; // string helper functions
function match($string1, $string2)
{
$string1 = trim($string1);
$string2 = trim($string2);
if (strcasecmp($string1, $string2) == 0) // are equal
{
return true;
} else {
return false;
}
}
?>
Before I had this as a static method to a String class, but this always seemed wrong to me... Which is the better alternative? I have a desire to categorise my helper functions, and want to know which is the better way to do it.
Edit
So how do I then access the match function if I have declared it in a namespace? How do I stop the namespace declaration, say if I include a file beneath it which declared a new namespace, would it automatically stop references to the first? And how do I go about returning to global namespace?
I'd put it in a namespace. A class is a describes a type in php, and though you maybe operating over a type with a similar name, it's not the same type, strictly speaking. A namespace is just a way to logically group things, which is what you're using a class to do anyways. The only thing you lose is extensibility, but as you said, it's only a collection of static methods.
If they're all string-related functions, there's nothing wrong with making them static methods.
A namespace would be the better choice if you've got a bunch of global functions and/or variables which you don't want cluttering up global scope, but which wouldn't make sense in a class. (I've got a class in my own code which would be a lot better suited to a namespace).
It's good practice to stick everything in some sort of container if there's any chance your code will get reused elsewhere, so you don't scribble on other people's global vars...
As for your edit there:
Namespaces are tied to the file they're defined in, IIRC. Not sure how this affects included files from there but I'd guess they aren't inherited.
You can call the global scope by saying ::trim().
Because namespaces are so new to php, people have been doing for a long time what you did - create a class, add static methods, and use the class as if it were a namespace. It looks to me as if you are thinking about it properly.
You would use classes to categorized some sort of functions on a certain dat. Like let say you have a Student class which will hold student information and student age and student ID number;and alose there some sort of methods that return and set these data.
Moreover, you would use namespace to categorized the Classes;let say now you have another class which handle the University registration for those students and alose the other classes for managing courses. Personaly, I would put all these classes under a category (i.e. namespace) called University.
Thus, it is not even a bad practice, also it gives you more readability in your code. And that would be more underestandable for other programmers if you are working in a group.
So personally I strongly suggest you use those in your project wherever you think it is proper to use it.
Ideally, it would be best to put functions in a namespace. If you depend on autoloading though, which only works for classes, you need to put them in one or more classes.

Categories