Code is great, but comments are better. If code is what tells a computer what to do, then comments are how you communicate your intent. If the logic for a function is very clearly communicated in the comments, it can be translated by another programmer into any other programming language. If a piece of code is well-commented throughout, then even without knowing all there is to know about the language or the rest of the classes being accessed at any given point, you can figure out what the code is doing. When you need to bring a new developer up to speed on your project, a huge factor in how quickly they’ll become useful is how well your project is commented.
I’m going to assume that you’re already familiar with how to create a comment, so this video is going to focus more on what and where to comment.
Probably the first and most important thing to comment are your functions and methods. These comments can significantly illuminate your API, and that can make it easier to find and re-use existing code or bring new developers up to speed.
PHP has an excellent support community dedicated to it, and out of that community came phpDocumentor – a handy free tool that will take your project and automatically generate an API for you. It will use your comments to flesh out that API, but only if you use a style of commenting known as “javadoc” or “doc-block”. Even without using this tool however, it’s a great convention to follow. Zend Studio, which I use for my own coding environment, automatically recognizes this style of comments and will assist in their creation.
The basic syntax of javadoc looks like this: {show prepared code segment with comment}
Notice that the first line contains a slash followed by 2 asterisks, and each line starts with an asterisk. The description of whatever is being commented is the first thing in the block. After that, you can use tags preceded by @ symbols to provide very specific information that programs such as phpDocumentor use.
There are a limited number of elements where phpDocumentor looks for and parses javadoc-style comments. I suggest you make a habit of placing these comments at the top of all of them. These include files, functions, defines and includes, as well as any global variables. And assuming your project is object-oriented, you should also place these comments above your class definitions, their methods, and their properties.
When documenting a function, as is the case here, your most important tags are ‘@param’ and ‘@return’. ‘@param’ tells the name and expected value type for each variable passed to the function (this information can also be gleaned to some extent from type-hinting, but not as broadly since as of PHP 5 type-hinting only includes null, array, and object types). ‘@return’ provides information about the type of value returned. In addition to those two, if your method can throw an exception, you should include a tag for ‘@throws’ for every type of exception your function might throw – the syntax is “@throws ExceptionType – conditions which will cause this exception to be thrown”.
Now in addition to those tags, javadoc officially recognizes many more. I won’t discuss all of them – there’s an exhaustive tutorial available online that I’ll point you to in a moment. But I will take you through the ones I find most helpful most often.
To reference another method elsewhere in your code, you can use ‘@see’. And in phpDocumentor this is really great, because if it recognizes what you’re linking to, it will actually create a hyperlink to the documentation of that other portion of your code. So for instance ‘@see GoToClass’ would create a link to the documentation for a class called ‘GoToClass’ if one exists in your project. And of course, it’s useful even if you don’t use phpDocumentor because it lets your reader know what other portions of the code use or are used by the thing you’re documenting.
When a project has lots of authors, it’s a very good idea to include a tag ‘@author’ in each of your contributions. Later, if someone has a question about how it works, they can see who wrote it and ask them to explain it.
At the beginning of each file, you can place a javadoc comment as well. In the automatically generated documentation, file or page-level comments have its own section. When you use it, you must include the ‘@package’ tag. The value in @package will specify a particular group of files that all relate to one another, and all appear within the navigation generated by the documentor for that package.
When you have to stop working on something before it’s finished, there’s a tag for that too. Use ‘@todo’ followed by a description of what still has to be written.
There are currently about 30 different tags recognized by phpDocumentor, and most other javadoc parsers will recognize them as well. You can learn about all of them by going to the phpdoc manual online.
Javadoc comments placed above your files, classes, functions, methods, and properties will really liven up your API if you generate one. And even if you don’t it’s going to make your code much easier to understand. But the other important places to comment are anytime you do something where simply looking at the code, it would be difficult to figure out what’s going on. As a general guide, if you call a function defined elsewhere, include a short comment about what that function should do. That way, the person trying to work on it doesn’t need to go and hunt down its definition in a separate file. The same is true if you invoke one of the more obscure PHP functions. And if you simply need to perform a task that requires some tricky logic, or is unlike the way things are done elsewhere in the project, write a short comment explaining what you did.
Personally, I find the best way to write my scripts is to start by outlining my logic within comments before I ever write my code. Then, I just place my code within the lines of logic where I’ve described what needs to happen. It helps me ensure my logic is good before I even start the actual coding, and when I’m done, I just leave the outline there for documentation.
December 08 2009 | Schmategories | Comments Off on A primer on good code commenting
PHP 5.3 included a couple of significant new features that are worth giving their own space to cover. These are “namespaces” and “late static bindings”. I’ll discuss late static bindings in the chapter on objects and classes, but in this video we’ll look at namespaces.
Something you will see fairly often in larger PHP applications is classes with names like: Doc_Event_Model_BuildHelper
This sort of name is common, and provides a couple handy features. For one, if it follows the typical convention, you know that within whatever directory classes are kept, there is probably a folder called ‘doc’ with a folder called ‘event’ with a folder called ‘model’ with a file called ‘BuildHelper.php’. And assuming it’s PHP 5 or later, then there is most likely an __autoload function that tells PHP which path to check when trying to load this class. The other useful trait is that it avoids naming collisions. In PHP, no 2 classes can have the same name (and neither can constants or functions).
The downside to this convention is that class names can get very long, and there isn’t a similar convention for constants or functions, which similarly can’t have more than one instance of the same name. As a result, large programs often won’t define functions or constants except as static methods or constants on these long-named classes. Namespaces give you an alternate way of relating the various parts of your code, and prevents naming collisions with unrelated components.
The most basic way to think about namespaces is to liken them to your file manager’s directory structure. If all of your files were in the same folder, then no 2 files could have the same name, and as you added files over time, the file names would need to get pretty long to avoid overwriting existing files. So instead, we can use directories to organize our files into smaller related groups. And when you need to refer to a file, you can use a relative path or an absolute path.
With namespaces, like directories, we arrange our code into related parts. When we refer to namespaced code, we also use absolute or relative names. To use the proper terminology, we refer to these names as either as ‘qualified’, ‘unqualified’, or ‘fully-qualified’.
For instance, in the namespace ‘Foo’, a call like ‘$a = new Bar()’ would actually attempt to create a new instance of ‘Foo\Bar’, meaning some class called “Bar” within the namespace “Foo”. And in this case, we would refer to “Bar” as an unqualified name, since it has no namespace qualifier preceding it.
On the other hand, a fully-qualified name is like an absolute path to a file in your directory. The system knows it’s fully-qualified because it begins with a “\” character. So, using the example above, we might write “$a = new \Foo\Bar()”. In both examples, PHP would interpret this as a call to create a new instance of the class “Bar” residing in the namespace “Foo”.
Another way to create a fully-qualified name is to use the special “namespace” keyword. In this context, it acts much like the “self” keyword for a class. We could change our code to “$a = new namespace\Bar()” and it would again do the same thing. The usefulness here is that you can write code that is totally agnostic about the actual namespace it resides in, so long as it does actually contain some class by the name of “Bar”.
A “qualified name” is analogous to a relative path to a file within a sub-folder. You can have sub-namespaces the same as you can have sub-folders. So, back to our previous example, suppose there was a sub-namespace within Foo called “AnotherFoo,” which also had a class called “Bar”. If we wanted to specify that we were using that class instead, we could write “$a = new AnotherFoo\Bar()”. Notice there’s no forward slash at the beginning of the class name. So, what we actually get, in terms of a fully-qualified name, would be \Foo\AnotherFoo\Bar.
PHP will convert unqualified and qualified names into fully-qualified names at compile time.
Now that we’ve explored terminology, let’s look at how we actually define our code within a namespace.
When you declare a namespace within a file, it must come at the very start of the file. The only exception PHP allows is a declare statement to identify the type of encoding for the file. Consider the following code:
<html>
<?php
namespace Joe {
…
}
this code throws a fatal error because of the line above the php tag.
However if this is how your file begins:
<?php
namespace Joe {
…
}
Then you’re fine.
When you declare a namespace, any files you include within that namespace will also be a part of it. If the file ‘mover.php’ contains the class ‘Mover’, then in the following code:
namespace Joe {
include(“mover.php”);
…
}
the fully-qualified name for the class Mover will actually be \Joe\Mover.
In the same way, if you include a file that also defines a namespace from within a namespace, then that included namespace is going to be a sub-namespace.
For instance, if the following lines begin a file included within the namespace declaration ‘A’
namespace B {
function do_something() {
…
}
…
}
then the fully-qualified call to that function would be \A\B\do_something().
To be really useful though, it would be nice to be able to avoid writing a number of separate ‘include’ calls, and simply use the power of PHP 5’s ‘__autoload’ capability. __autoload is a special global function that PHP calls when an unrecognized class is referred to, instead of simply throwing an error (a la PHP 4). This function attempts to include a file based on the name of the class, in hopes that the referenced class will be found there.
Creating a custom __autoload function will be discussed in a separate video, but one of the most wonderful things about PHP 5.3 is that most of us won’t need to write one – the default __autoload function included with SPL already understands namespaces.
To enable, just call ‘spl_autoload_register()’ without paramters. If you want to specify a certain directory containing your classes, use ‘set_include_path’ to ensure that the autoload function checks there. And you can make sure that php uses a specific extension, such as ‘.class.php’ by calling ‘spl_autoload_extensions()’. Check out this example:
set_include_path(get_include_path() . ‘/classes’);
spl_autoload_extensions(‘.class.php’);
spl_autoload_register();
Now, whenever the code tries calling a class that hasn’t been included yet, say ‘\Useful\Class\Test’, the code will look inside the folder ‘classes/Useful/Class’ for a file called ‘Test.class.php’. And if it finds it, and the file contains a definition for the class ‘Test’ within the namespace ‘\Useful\Class’, then the class will be used seamlessly, and no explicit include file will be necessary.
Now it’s true that you can write your own __autoload function to do the same exact thing, but the spl_autoload function, since it’s actually written in C and not PHP, is going to be slightly faster. My advice is, whenever possible, try to create your directory structure in such a way as to make use of this handy default behavior.
December 06 2009 | PHP tutorial scripts | Comments Off on What's new in PHP 5.3 – Namespaces