In my last blog post, I introduced ContractLib, a simple programming by contract library that I’ve created for PHP 5.3 onwards. And I promised some examples :)

Installing ContractLib

ContractLib is available from the Phix project’s PEAR channel. Installing it is as easy as:

[code lang=”bash”]
$ pear channel-discover pear.phix-project.org
$ pear install -a phix/ContractLib
[/code]

At the time of writing, this will install ContractLib-2.1.0. We use semantic versioning, so these examples will continue to work with all future releases of ContractLib-2.x.

Adding ContractLib To Your Project

Assuming you’re using a PSR-0 compatible autoloader, just import the Contract class into your PHP file:

[sourcecode language=”php”]
use Phix_ProjectContractLibContract;
[/sourcecode]

Adding A Pre-condition Contract To Your Method Or Function

Take a trivial method like this:

[code lang=”php”]
class ActionToApply
{
public function appendNow($params)
{
$params[] = time();
}
}
[/code]

This method works fine … until someone passes a non-array as the parameter. At that point, your code stops working – not because your code is wrong, but because someone used it in the wrong way. This is a classic cause of buggy PHP apps. Thankfully, it’s very easy to address using ContractLib.

If we were certain that the $params parameter was always an array, then we can keep the method itself extremely simple and clean. We can ensure that by adding a pre-condition using ContractLib.

[code lang=”php”]
use Phix_ProjectContractLibContract;

class ActionToApply
{
public function appendNow($params)
{
Contract::Preconditions(function() use ($params)
{
Contract::RequiresValue(
$params,
is_array($params),
‘$params must be an array’
);
});

// original method code continues here
$params[] = time();
}
}
[/code]

Now, if someone passes in a non-array, the caller will automatically get an E5xx_ContractFailedException, which makes it clear that the fault is in the caller’s code … not your’s.

PHP 5.4’s upcoming support for better type-hinting is another way to catch this kind of error, but not only does ContractLib work today with PHP 5.3 (which means you don’t have to wait to migrate to PHP 5.4), but also that you can write tests for anything, not just the checking that’s built into PHP.

This means you can make your code much more robust, by tightening up on the quality of the parameter passed into your code by other programmers. To extend our example, we might decide that an empty array is also unacceptable:

[code lang=”php”]
use Phix_ProjectContractLibContract;

class ActionToApply
{
public function appendNow($params)
{
Contract::Preconditions(function() use ($params)
{
Contract::RequiresValue(
$params,
is_array($params),
‘$params must be an array’
);
Contract::RequiresValue(
$params,
count($params) > 0,
‘$params cannot be an empty array’
);
});

// original method code continues here
$params[] = time();
}
}
[/code]

The point here is that we can go way beyond type-hinting checks (important as they are) and look inside parameters to make sure they are suitable.

Here’s a real example from Phix’s CommandLineLib:

[code lang=”php”]
use Phix_ProjectContractLibContract;

class CommandLineParser
{
// …

public function parseSwitches($args, $argIndex, DefinedSwitches $expectedOptions)
{
// catch programming errors
Contract::Preconditions(function() use ($args, $argIndex, $expectedOptions)
{
Contract::RequiresValue(
$args,
is_array($args),
‘$args must be array’
);
Contract::RequiresValue(
$args,
count($args) > 0,
‘$args cannot be an empty array’
);

Contract::RequiresValue(
$argIndex,
is_integer($argIndex),
‘$argIndex must be an integer’
);
Contract::RequiresValue(
$argIndex,
count($args) >= $argIndex,
‘$argIndex cannot be more than +1 beyond the end of $args’
);

Contract::RequiresValue(
$expectedOptions,
count($expectedOptions->getSwitches()) > 0,
‘$expectedOptions must have some switches defined’
);
});

// method’s code follows on here …
}
}
[/code]

In this real-life code, we start off by checking for basic errors first (by making sure we’re looking at the right type for each parameter), and then we follow up with more specific tests, that ensure that we have data that we’re happy to work with. We’ve done these tests at the start of the method, so that it isn’t cluttered with error checking, which makes our code much cleaner that it might otherwise be. And, because all the tests are in one really easy to spot block, anyone reading your code can immediately see what they have to do to meet the contract you’ve created.

Because these tests are just plain-old PHP code, and don’t rely on annotations or any other such nonsense, the contracts you create and enforce are limited only by your choices.

But Aren’t All Those Tests Slow?

They are. PHP’s getting better and better at this, but function/method calls have always been painfully slow in PHP. I’m afraid that if you want robust code, you can’t have it for free. (You can in C, but that’s a topic to discuss over a decent whiskey at a conference).

I’ve done key two things with ContractLib to keep the runtime cost down:

  1. Contract::Preconditions() accepts a lambda function as its parameter. Your contract’s tests go inside this lambda function, and Contract::Preconditions() only calls the lambda function if contracts are enabled.
  2. By default, ContractLib does not enable contracts. You have to choose to do so by calling Contract::EnforceWrappedContracts().

This keeps the overhead down to just one method call (to Contract::Preconditions()) when contracts are not enabled. It isn’t as good as having no overhead, but it’s cheaper than the developer time lost trying to track down bugs in code that always assumes the caller can be trusted to do the right thing every time.

Any Questions?

I hope these examples have given you an idea on how to get started with ContractLib. If you have any questions or suggestions, please let me know, and I’ll do my best to answer them.

Be the first to leave a comment »

The Phix Project Has A New Home

Posted by Stuart Herbert on September 23rd, 2011 in Examples, phix, Toolbox.

Phix now has a new home, as I’ve recently left Gradwell. And a new PEAR channel. And an awesome new logo thanks to Jeremy and Kerry from Magma Digital. And a roadmap on Trello.

And, if you’re using either Ubuntu or Fedora as your dev desktop/laptop, a new one-line installer that takes care of those pesky system-level dependencies that the PEAR Installer can’t help you with :)

How To Move To The New PEAR Channel

If you have already installed an older version of Phix from pear.gradwell.com, you’ll need to run the following commands in order to switch over to our new PEAR channel pear.phix-project.org.

$ sudo pear uninstall Gradwell/ComponentManager 
Gradwell/ComponentManagerPhpLibrary Gradwell/ComponentManagerPhpWebapp
Gradwell/ComponentManagerPhpDocbook Gradwell/ComponentManagerShared
Gradwell/ConsoleDisplayLib Gradwell/CommandLineLib
Gradwell/ValidationLib Gradwell/phix 
Gradwell/Autoloader Gradwell/ExtenderLib

Then, visit the installation instructions on phix-project.org. Try out our new one-line installers for Ubuntu or Fedora. (Got a one-line installer for another platform? Fork the website on GitHub and send me a pull request :)

If all goes well, you should end up with phix-0.13 installed on your computer:

$ pear list -c phix | grep phix
phix                       0.13.2  stable
phix4componentdev          0.13.2  stable

If You Have Components That Depend On Phix’s Components …

… you’ll need to edit their package.xml files:

  • Swap any references to pear.gradwell.com to pear.phix-project.org.
  • Check any <min> and <max> version numbers of any Phix components you depend on, as I’ve bumped all the version numbers.

All of Phix’s components now live in the Phix_Project namespace. You’ll need to update any classes that ‘use’ any of the Phix classes accordingly.

Be the first to leave a comment »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

This is a guest post by Martin Wernståhl. Martin is a university student at Chalmers University of Technology, Sweden, currently studying the first year of Engineering Physics. He started programming at an age of 9 by writing Not-Quite-C for LEGO robots. Since then he has been programming a little bit of everything until he started with PHP around five years ago. Using CodeIgniter at first, he soon started to write libraries and hack the core of CodeIgniter until he felt that it was too limiting and resorted to starting to experiment with creating his own ORM tools (IgnitedRecord, discontinued as he no longer uses CodeIgniter and RapidDataMapper, development paused because of indecision related to syntax) and lately he has gone back to experimenting with creating a very modular PHP framework. Martin has also been a very enthusiastic supporter and tester of Phix and ComponentManager since their first releases.

If you would like to contribute a guest post about PHP components, please poke @stuherbert on Twitter.

How to Host a PEAR Channel on GitHub

GitHub has a feature called GitHub pages which they introduced about 2.5 years ago. This enables you to host static files located in a specific branch in a repository (gh-pages) on GitHub’s webserver. This can also be used to host a PEAR channel and can be very useful for smaller projects or if you don’t have the time or money to configure a specific server for PEAR. An added bonus is that the content of your PEAR channel server will be versioned by git.

For an example of a GitHub hosted PEAR channel, see the Inject Framework’s PEAR channel page.

The Repository

First, create a new repository on GitHub for your PEAR channel. You may now wonder why I wrote a new repository, this is because of the fact that it is usually better to separate your projects and the PEAR channel repository because of the difference in content, plus, the repository name will be a part of the URL. You might also not want to limit which packages you can put in the channel because of the naming of the parent repository.

A recommended name for the new repository is pear, as that will be equivalent with ${yourusername}.github.com/pear. A must is that the name is lowercase, as GitHub’s URLs are case sensitive.

For an example repository hosting a PEAR channel, see the Inject Framework’s PEAR repo on GitHub.

Create Your Repository Locally

To create the repository we are going to use Pirum. Pirum is a PEAR channel server "generator" which generates static files which can be used by any PEAR installer to install your packages.

So, create a folder for your pear repository and then place a pirum.xml file there:

 
<?xml version="1.0" encoding="UTF-8" ?>
<server>
    <name>${yourusername}.github.com/${pear_repository}</name>
    <summary>${page_title}</summary>
    <alias>${short_prefix}</alias>
    <url>http://${yourusername}.github.com/${pear_repository}</url>
</server>

yourusername and page_title are fairly self-explanatory. pear_repository is the name of the GitHub repository you will store your PEAR channel in. But what does the <alias> tag do?

The contents of the <alias> tag is the channel alias which can be used instead of the contents of <name> when installing PEAR packages after you have run pear channel-discover. An example is the InjectFramework: instead of injectframework.github.com/pear/InjectStack you write injectfw/InjectStack [1].

Then we create our new Git repository, run pirum build . to create the PEAR channel, then link our repository with GitHub and finally create and push the gh-pages branch:

 
cd my/pear/repository
git init
pirum build .
git remote add origin git@github.com:${yourusername}/${pear_repository}.git
git add *
git commit
git branch gh-pages
git checkout gh-pages
git push -u origin master
git push origin gh-pages

Now you should receive a notification from GitHub (can be sent via email too depending on your notification settings) telling you that your page build was successful [2]. It might take as long as up to 10 minutes before your pages will appear on http://${yourusername}.github.com/${pear_repository} the first time you push your changes. Following pushes should update the pages almost instantly.

Now on to see if it works as it should; if pear channel-discover http://${yourusername}.github.com/${pear_repository} does not return any errors, everything went fine. You might want to check http://${yourusername}.github.com/${pear_repository} using a browser to see if it has been uploaded first, you will get a 404 if it is not.

Creating A PEAR Package Using Phix

If you are using Phix to help maintain your project, you have an environment which already is configured for generating PEAR packages. But first you have to configure Phix so that it will generate the proper package.xml file:

First we edit the project.channel value in build.properties:

 
project.channel=${yourusername}.github.com/${pear_repository} 

Then we go on to the package.xml file, most of the everyday stuff (like adding files etc.) will be handled by Phix, but the descriptions, version history and package requirements need to be edited manually. See the PEAR package.xml documentation for more information.

Don’t forget to bump version info in build.properties and change-log information in package.xml when you are creating a new package version.

When you have got the package.xml and build.properties configured properly, use the command phing pear-package to create a PEAR package which will be placed in dist/${<packagename>}-X.Y.Z.tgz

Adding The Package To Your PEAR Channel

To add a PEAR package, you just use:

 
pirum add my/pear/repository my_pear_package-X.Y.Z.tgz
cd my/pear/repository
git commit -a -m "Added my_pear_package-X.Y.Z"
git push

Then visit ${yourusername}.github.com/${pear_repository} with your browser to see a list of all the uploaded packages.

Conclusion

In the beginning there was only pear.php.net, the only resource for PEAR packages in the world. Then other package channels arrived, and publishing your own PEAR package channel became really easy with Pirum. Now you don’t even need your own web-server to host it; you can host it on GitHub, along with the source code for your PEAR package.

Now, if we only can get some kind of PEAR channel aggregator or similar thing to avoid having to use channel-discover for every new tool we want to install…

Footnotes

  1. The channel name must match the regular expression [a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*(/[a-zA-Z0-9-]+)*
  2. You might want to turn off email notifications for successful page builds, because the emails can easily pile up if you make many pushes.
Be the first to leave a comment »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’m now going under the bonnet of our components, and looking at the different file roles that the PEAR installer expects to find when we distribute our component as a PEAR-compatible package. It isn’t very often that a component needs to ship web pages too, but should the need arise, here’s how to do it.

What Is A Web Page?

A web page (the ‘www’ file role supported by the PEAR Installer) is any sort of content meant to be served up by web server software such as Apache. This can be a HTML file, a PHP script, CSS files, Javascript files, images … you name it.

Where Do Web Pages Go Inside Your Component’s Structure?

If we look at the PhpInfo component, you’ll find that the web pages live in the src/www/ folder:

src/www/ is meant to be a folder that holds all of the web pages (and related content) that you want installed into the computer system.

Where Does The PEAR Installer Install The Web Pages?

When you use the PEAR installer to install your component:

$ pear install phix/PhpInfo

all of the web pages get installed into /usr/share/php/www/ on your computer:

The PEAR installer’s behaviour here is almost identical to command-line scripts; the installer installs your web pages directly into the main www_dir folder. This does create the potential for clashes, where two or more packages want to install files with identical names. In practice, PHP components include web pages so rarely that the problem is unlikely to happen.

The test file src/www/phpinfo.php therefore ends up installed onto your computer as /usr/share/php/www/phpinfo.php.

There’s always the possibility that some Linux distros (and Mac OS X) will install doc files into a different folder. You can see where the PEAR installer will put these files on your computer by running:

$ sudo pear config-show | grep www_dir
PEAR www files directory   www_dir          /usr/share/php/www

How Do I Get Apache To Serve These Files?

By default, and for very good reasons, Apache does not serve content directly from /usr/share/php/www/. You will need to copy any files from /usr/share/php/www/ to your website folders (normally found under /var/www/) before they can be used.

8 comments »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’m now going under the bonnet of our components, and looking at the different file roles that the PEAR installer expects to find when we distribute our component as a PEAR-compatible package. One of the most important file roles allows you to ship your tests with your package – and it’s vital that this is something that you get in the habit of doing routinely.

Test Your Code, And Ship Your Tests

If you want other developers to re-use your code in their projects, it is essential that you earn their trust. Trust has to be earned over time, by establishing a track record of dependability. There are many things you need to do to establish such a reputation, such as semantic versioning to flag backwards-compatibility breaks, and writing unit tests to prove that your code works as expected.

Although the PEAR Installer has long supported shipping unit test code, to date the PHP community hasn’t really embraced this, and it is still very rare for a PEAR package to include unit tests when downloaded. This is also compounded by unfortunate legacy choices in some Linux distributions (ubuntu bug, fedora bug), where unit test code currently ends up being installed under the same directory tree as the main code from the PEAR packages – something that only really matters since the PHP Community started to adopt PSR-0 as the standard for autoloading.

What Are PHP Tests?

PHP tests (the ‘test’ file role supported by the PEAR Installer) are executable tests. There is currently no formal standard for these tests; however, PHPUnit has emerged as the community’s de facto standard for unit tests, and is the approach that the PHP components skeleton supports out of the box to make life much easier for you.

Just as important as shipping tests is making sure that it is extremely easy for someone who knows nothing about your code to safely and reliably execute any tests that you ship. The components skeleton handles much of this for you, by including a PHPUnit bootstrap.php file, and a build.xml file with full instructions on how to execute the tests.

However, it is important that you write your tests in a way that doesn’t rely on anything that your users won’t have installed or configured.

Where Do Tests Go Inside Your Component’s Structure?

If we look at the CommandLineLibrary component, you’ll find that the unit test files live in the src/tests/unit-tests/ folder:

Important notes:

  1. The folder structure underneath src/tests/unit-tests exactly matches the folder structure for both PHP scripts and PHP files under the src/ folder.
  2. Each unit test script is designed for PSR-0 autoloading, just like the PHP scripts that they test.
  3. Each unit test script ends in the word ‘Test’. This is a convention that is supported in IDEs such as Netbeans.

Where Does The PEAR Installer Install The Tests?

When you use the PEAR installer to install your component:

$ pear install phix/CommandLineLib

all of the test files get installed into /usr/share/php/tests/<package-name> on your computer:

The PEAR installer’s behaviour here is different to both command-line scripts and PHP code; the installer creates a sub-folder with the name of your package, and then installs your test files into this sub-folder, and not into the main test_dir folder. This isn’t a problem in practice, as long as you are aware of the different behaviour here.

The test file src/php/unit-tests/Phix_Project/CommandLineLib/CommandLineParserTest.php therefore ends up installed onto your computer as /usr/share/php/tests/CommandLineLib/Phix_Project/CommandLineLib/CommandLineParserTest.php.

There’s always the possibility that some Linux distros (and Mac OS X) will install doc files into a different folder. You can see where the PEAR installer will put these files on your computer by running:

$ sudo pear config-show | grep test_dir
PEAR test directory   test_dir          /usr/share/php/tests

What About Other Kinds Of Test Code?

In the PHP component skeleton, the src/tests/functional-tests folder is available for anyone who wants to add any automated testing to prove that their app works. Selenium is a tool that might help with this.

There’s also the src/tests/integration-tests folder available for anyone who wants to maintain a strict separation between unit tests (which, technically, should prove that a single class works as required) and integration tests (which, technically, should prove that a collection of classes work together as required, especially across system boundaries).

At the time of writing, the component skeleton doesn’t do anything with code inside these folders. Patches are most welcome!

10 comments »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’m now going under the bonnet of our components, and looking at the different file roles that the PEAR installer expects to find when we distribute our component as a PEAR-compatible package. Documentation is very important to your users, but what you ship in your PEAR-compatible package should really be just the bare minimum.

Documentation Is The Missing Feature

I’m sorry to report that there is currently a large gap when it comes to handling of documentation in PHP’s PEAR-driven packaged ecosystem.

  • There is no standard markup format(s) for documentation shipped in packages.
  • There is no standard structure to install a package’s documentation into.
  • The PEAR installer does not gather up all of the installed documentation to generate a single PHP Manual-style local website of all of the installed PEAR-compatible packages. This would be a killer feature for someone to create.
  • The PEAR installer does not auto-generate PHPdoc-compatible documentation from all of the installed PEAR-compatible packages after installation.

The pear.php.net website hosts documentation for the PEAR project, but at the time of writing this documentation isn’t shipped with PEAR (or PEAR-compatible) packages.

During the rehersals for my Beyond Frameworks talk, my test audience was crystal clear about the importance of documentation. The PHP Manual is undoubtedly one of PHP’s killer features, and it rightly sets a high standard for the documentation that developers should expect to both create and have provided to them. The process and toolset for documenting PEAR-compatible packages isn’t yet a mature practice, and there’s definitely an opportunity for someone to step up and plug this gap.

This doesn’t mean that it’s a waste of time documenting your packages; it just means that, today, you’re better off including some documentation in your package, and publishing the rest of the docs somewhere else.

What Are The Docs You Should Include In Your Package?

Every PHP component should, as a minimum, ship the following documentation inside the PEAR-compatible package:

  1. LICENSE.txt – what copyright and licensing terms apply to the package
  2. README.txt – general information about the package, and where to find the package’s main website

The LICENSE.txt file is absolutely essential: it tells responsible developers whether or not they can legally use your work in their project, and just as important it sets the scene for whether or not anyone can fork your component should you decide not to maintain it any more. This file should contain the full text of the license. If you are not sure which license to use, the PHP ecosystem strongly prefers the new BSD license or the MIT license.

(You should also include license details in your docblocks at the top of your source files; that is a topic for later in the series).

The README.txt file is also essential: at the very least, it tells developers where to go to find your component’s website and full documentation. If you publish your source code via GitHub, you can write this file as README.md (using GitHub’s flavour of Markdown) and GitHub will automatically pick up the file and display it on your repository’s homepage (as an example, see phix’s homepage).

Quite a few existing PHP components also include a CREDITS.txt file, although some PHP components prefer to publish this information on their website instead.

Where Do Docs Go Inside Your Component’s Structure?

If we look at the ComponentManagerPhpLibrary component, you’ll find that the essential documentation files actually live in the component’s top-level folder:

The component skeleton will automatically pick up any files in the top-level folder that match the patterns ‘*.txt’ or ‘*.md’.

Where Does The PEAR Installer Install The Docs?

When you use the PEAR installer to install your component:

$ pear install phix/ComponentManagerPhpLibrary

all of the documentation files get installed into /usr/share/php/docs/<package-name> on your computer:

The PEAR installer’s behaviour here is different to both command-line scripts and PHP code; the installer creates a sub-folder with the name of your package, and then installs your doc files into this sub-folder, and not into the main doc_dir folder. This isn’t a problem in practice, as long as you are aware of the different behaviour here.

The doc file README.md therefore ends up installed onto your computer as /usr/share/php/docs/ComponentManagerPhpLibrary/README.md.

There’s always the possibility that some Linux distros (and Mac OS X) will install doc files into a different folder. You can see where the PEAR installer will put these files on your computer by running:

$ sudo pear config-show | grep doc_dir
PEAR documentation directory   doc_dir          /usr/share/php/docs

Okay … So What Should We Do About Proper Documentation?

Anyone getting started with your component clearly needs a lot more documentation than a LICENSE and a basic README. Unfortunately, as discussed at the start of this article, today the PEAR installer has poor support for shipping the sort of high-quality, in-depth documentation that your users both expect and deserve.

For now, the right thing to do is to publish your documentation on a website. I’m going to look at that in detail later in this series, after I have finished looking at the rest of the file roles supported by the PEAR installer.

Be the first to leave a comment »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’m now going under the bonnet of our components, and looking at the different file roles that the PEAR installer expects to find when we distribute our component as a PEAR-compatible package. Although the vast majority of your components will simply be libraries of code, sometimes you might need to ship data files for them to operate on. Thanks to the PEAR installer’s data role, this is possible.

What Is A Data File?

A data file (the ‘data’ file role supported by the PEAR installer) is an arbitrary file that your code either reads from, or (in the case of images et al) serves up to other programs.

There are some important practices and limitations that you need to follow to avoid any disappointments or nasty surprises:

  • Data files should not be PHP code that you plan on executing.

    Your users expect your code to be in the standard place (which is /usr/share/php for popular Linux systems, or vendor/php/ in the per-app sandbox). Follow the rule of no surprises, and make sure you put your code where your users expect to look for it.

    For example, PEAR’s HTTP2_Request component ships PHP code in its data folder, code to rebuild the Public Suffix List (which is, itself, a data file). The chances are that most of HTTP2_Request’s users are unaware that the data folder exists, and that there is code in the data folder which they might need to use. Another example is ezComponent’s ConsoleTools, which ships a UML diagram for ezComponents in its data folder. This probably belongs in the docs folder, if it is meant to be read by developers using ConsoleTools. My local /usr/share/php/ contains many more relevant examples; yours’ probably does too.

    Our component skeleton offers an alternative approach, to ship generate-list.php a properly-installed command-line program, or perhaps as a drop-in command for phix.

  • Data files cannot be written to; your code should treat them as read-only.

    When your data files are installed for system-wide use, the files are owned by the root user. Unless there is an almighty security cock-up, your code will never ever actually get to run with the root user’s security privileges. If your code tries to write to these data files, it will generate a runtime error.

    But this won’t show up when you unit-test your code. So remember, and don’t write the code in the first place :)

Where Do Data Files Go Inside The Component’s Structure?

If we take a look at the ComponentManagerPhpLibrary component, you’ll find the data files are inside in the src/data/ folder. These are the skeleton files used for a PHP library component.

src/data/ is meant to be a folder that holds the data files that you want installed into the computer system.

Where Do Data Files Get Installed?

When you use the PEAR installer to install your component:

$ pear install phix/ComponentManagerPhpLibrary

all of the files in your component’s src/data/ folder gets installed into /usr/share/php/data/<package-name> on your computer:

The PEAR installer’s behaviour here is different to both command-line scripts and PHP code; the installer creates a sub-folder with the name of your package, and then installs your data files into this sub-folder, and not into the main data_dir folder. This isn’t a problem in practice, as long as you are aware of the different behaviour here.

The data file script src/data/php-library/README.md therefore ends up installed onto your computer as /usr/share/php/data/ComponentManagerPhpLibrary/php-library/README.md.

There’s always the possibility that some Linux distros (and Mac OS X) will install data files into a different folder. You can see where the PEAR installer will put these files on your computer by running:

$ sudo pear config-show | grep data_dir
PEAR data directory            data_dir          /usr/share/php/data

If you want to read these data files from your PHP code, you cannot safely hard-code the final installation location into your scripts; it will vary from OS to OS, and will also be different again if your component is installed into a vendor directory. You’ll need to locate these files using a different technique.

How Do I Locate The Data Files From My PHP Code?

Take a look at the top of the LibraryComponentFolder class from the ComponentManagerPhpLibrary component:

[code lang=”php”]
class LibraryComponentFolder extends ComponentFolder
{
const DATA_DIR=”@@DATA_DIR@@/ComponentManagerPhpLibrary/php-library”;
[/code]

@@DATA_DIR@@ is a token that, at runtime, the PEAR installer expands to be the fully-qualified path to the top of the computer’s data_dir. Underneath that, you need to remember to add your component’s name to the path, otherwise you’ll be scratching your head and wondering why you can’t find the data files!

(The full instructions that tell the PEAR installer to expand this token are added to your component’s package.xml file when we build the PEAR-compatible package. I’ll look at the final package.xml file in detail towards the end of this series of blog posts).

How Do I Unit Test PHP Code That Relies On Data FIles?

There is one important downside to this technique; any unit tests that rely on loading data from your data directory are going to fail, because @@DATA_DIR@@ is only expanded when the PEAR installer installs your component. At the time of writing, I don’t have an easy solution for this, but leave it with me, and I’ll find a solution for this before the end of this series of blog posts.

Be the first to leave a comment »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’m now going under the bonnet of our components, and looking at the different file roles that the PEAR installer expects to find when we distribute our component as a PEAR-compatible package. One of the useful file roles allows us to install new command-line programs (such as PHPUnit, or Phix) onto a computer for everyone to use.

What Is A Command-Line Program?

A command-line program (the ‘script’ file role supported by the PEAR installer) is a PHP script that your users run from inside Terminal (or Command on Windows). It allows you to put powerful tools in the hands of your users.

You can also run them as scheduled jobs via cron.

Where Do Command-Line Scripts Go Inside The Component’s Structure?

If we take a look at the phix component, you’ll find the command-line program itself in the src/bin/ folder:

src/bin/ is meant to be a folder that holds the commands that you want installed into the computer system.

In theory, you could put sub-folders under here, but this is not supported. If you look at phix’s actual code, you’ll see that the phix command-line program loads code that exists in the src/php/ folder of the component (and is installed into /usr/share/php/ when the PEAR installer installs the component). Your classes should go in src/php/ just like with any other component.

Where Do Command-Line Programs Get Installed?

When you use the PEAR installer to install your component:

$ pear install phix/phix

all of the files in your component’s src/bin/ folder gets installed into /usr/bin on your computer:

The command-line script src/bin/phix therefore ends up installed onto your computer as /usr/bin/phix.

The reason why the PEAR installer installs your PHP code under /usr/bin/ is because this folder is normally part of a user’s search path in Terminal. That allows users to run your command-line program simply by:

$ phix

without having to specify the full path to your command-line program.

I haven’t seen it personally, but there’s always the possibility that some Linux distros (and Mac OS X) will install command-line programs into a different folder. You can see where the PEAR installer will put these files on your computer by running:

$ sudo pear config-show | grep bin_dir
PEAR executables directory            bin_dir          /usr/bin

How Do I Make My Command-Line Program Executable?

You’re probably used to running PHP scripts from the command line like this:

$ php ./my-script.php

but for command-line programs, you don’t want your users having to remember to run everything through the PHP interpreter each time.

UNIX (and UNIX-like operating systems such as Linux) have a long tradition of writing command-line programs using scripting languages. If you put a shebang (the characters #! – hash, pling) at the top of your script, you can tell your operating system how to execute your script.

#!/usr/bin/env php
<?php

# PHP code goes here ...

The line #!/usr/bin/env php tells your operating system to use the PHP CLI interpreter (wherever it is in your Terminal’s path) to run this script. Using /usr/bin/env in this way normally makes your script portable across different Linux distros.

Be the first to leave a comment »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’m now going under the bonnet of our components, and looking at the different file roles that the PEAR installer expects to find when we distribute our component as a PEAR-compatible package. To get started, I’m going to start with the obvious file role: the PHP code that a component is all about.

What Is PHP Code?

PHP code (the ‘php’ file role supported by the PEAR installer) is your component’s PHP code. This is the code that you want everyone to download and install and then include into their own PHP apps.

Where Does PHP Code Go Inside The Component’s Structure?

If we take a look at the CommandLineLib component, you’ll find all of the PHP code for this component under the src/php/ folder:

src/php/ is meant to be the top of a tree structure that any PSR0-compliant autoloader could load from:

  • The first level of folders under src/php/ is (by convention) the name of the vendor of the code. For CommandLineLib, the vendor is Phix_Project.
  • The second level of folder onwards can be whatever you need them to be. By convention, for our components at work, we are using the second level of folders to be the name of the component, in this case CommandLineLib. This works really well as you start to build up a larger number of components in your PEAR channel.
  • And eventually, you get down to the actual class definitions themselves.

The PHP class Phix_ProjectCommandLineLibCommandLineParser therefore ends up in the file src/php/Phix_Project/CommandLineLib/CommandLineParser.php.

Where Does PHP Code Get Installed?

When you use the PEAR installer to install your component:

$ pear install phix/CommandLineLib

all of the files in your component’s src/php/ folder gets installed into /usr/share/php on your computer:

The PHP class Phix_ProjectCommandLineLibCommandLineParser therefore ends up installed onto your computer as /usr/share/php/Phix_Project/CommandLineLib/CommandLineParser.php.

The reason why the PEAR installer installs your PHP code under /usr/share/php/ is because this folder is normally part of PHP’s include_path. That allows developers to include your code simply by doing:

[code lang=”php”]
include “Phix_Project/CommandLineLib/CommandLineParser.php”;
[/code]

or, better still, by using a PSR0-compliant autoloader, and then simply attempting to create a new instance of the class:

[code lang=”php”]
// load the PSR0-compliant autoloader
require_once “psr0.autoloader.php”;

// create a new command line parser
$parser = new Phix_ProjectCommandLineLibCommandLineParser();
[/code]

Some Linux distros (and Mac OS X) will use /usr/lib/php/ instead of /usr/share/php/. You can see where the PEAR installer will put these files on your computer by running:

$ sudo pear config-show | grep php_dir
PEAR directory                 php_dir          /usr/lib/php
Be the first to leave a comment »

In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

In previous articles, I’ve introduced you to the component skeleton that phix creates for you when you run the phix php-library:init command. Our skeleton is designed to be extremely clean, so that it is very easy to automatically generate your PEAR-compatible component and its package.xml file, so that you don’t have to maintain it yourself (a process which would only end in tears).

At the heart of our skeleton, are the design constraints imposed by the PEAR installer, and that means the way it handles files differently depending on the file’s role.

What Are File Roles?

A file’s role is simply a way of telling the PEAR installer where you want the file installed. The PEAR installer supports the following file roles:

  • data – any data files that your component needs to read at run-time
  • doc – documentation about your component
  • php – your PHP code
  • script – any command-line scripts your component includes
  • test – your (hopefully, PHPUnit-based) tests
  • www – PHP code to be served by Apache

… plus a few more that are of no interest to authors of PHP components.

Where Do I Put Files For Each Role?

To make it extremely easy for the phing pear-package command to auto-generate your package.xml file, there’s a folder in our component skeleton for each type of file.

Here’s a handy summary showing you where to put your files inside your component, based on their role:

  • data – goes in the src/data/ folder
  • doc – goes in the src/doc/ folder
  • php – goes in the src/php/ folder
  • script – goes in the src/bin/ folder
  • test – goes in the src/tests/unit-tests/ folder
  • www – goes in the src/www/ folder

In the next few articles, I’m going to look at each of these file roles in turn, and show you in detail how the PEAR installer treats them, and how to work with them in your own components, starting with the php role.

Be the first to leave a comment »
Page 1 of 3123

This Month

July 2015
M T W T F S S
« Mar    
 12345
6789101112
13141516171819
20212223242526
2728293031