Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


Composer support #646

merged 18 commits into from

17 participants

Clay Loveless Sebastian Bergmann Rafael Dohms Mickaël Andrieu Adrien Brault Tony R Quilkey Christophe Coevoet Drak Markus Bachmann Peter Horne Michi Lehr Taufan Aditya Luis Cordova Jordi Boggiano Gasol Wu demonkoryu Andreas Hoffmann
Clay Loveless

As discussed in #522, this set of changes adds support for composer installation.

The package-composer.json file, coupled with package.xml and the package2composer script that is part of the Conductor package at is all that is needed to update the composer.json file.

Simply run package2composer in the top level of the checkout to regenerate composer.json to reflect changes made to package.xml

Suggestion: Link your repository at It's a one-time GitHub Service hookup, which will keep those using composer up to date as you produce releases using your normal process.

Sebastian Bergmann sebastianbergmann merged commit 9576cb3 into from
Sebastian Bergmann

Thank you, Clay, for your work on this! I hope that everyone interested in Composer support for PHPUnit appreciates it.

I merged all your pull requests, created an account on Packagist ( and added the service hook to all projects for which you sent pull requests.

Rafael Dohms

@sebastianbergmann you need to add the repositories themselves also via the submit page: just input the github url.

Sebastian Bergmann

I would if I could: keep getting 504 Gateway Time-out errors on Will try again later.

Mickaël Andrieu

Good Job !

Adrien Brault

Tried to use it with an exisiting SF2 project, and it failed because vendor/autoload.php is required twice (bin/phpunit and app/autoload.php). Works with this fix though composer/composer#1106 ...

Adrien Brault

I removed phpunit from my composer.json, and tried to update/install, and it fails because the phpunit's vendor directory was modified.
Not sure if the issue comes from composer or phpunit.

  Source directory vendor/phpunit/phpunit has uncommitted changes.  
➜  project git:(master) ✗ cd vendor/phpunit/phpunit
➜  phpunit  git status
# Not currently on any branch.
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#   modified:   phpunit.bat
no changes added to commit (use "git add" and/or "git commit -a")
➜  phpunit  git diff
diff --git a/phpunit.bat b/phpunit.bat
old mode 100644
new mode 100755
Tony R Quilkey

Not working here either. Dependencies are not resolving:

  Problem 1
    - Installation request for phpunit/phpunit dev-master -> satisfiable by phpunit/phpunit dev-master.
    - phpunit/phpunit dev-master requires phpunit/php-file-iterator >=1.3.1 -> no matching package found.
Rafael Dohms

@adrienbrault that is a composer issue, remove the phpunit folder from vendors and start clean.

@trq libraries still need to be added to Packagist, its having issues, hang on.

Rafael Dohms

@sebastianbergmann i see the first packages coming in so i'm guessing its working.

Christophe Coevoet

@adrienbrault to fix the issue, the .bat file should be executable in the phpunit repo so that a chmod done by composer for the bin does not change the repo.

@trq your issue may be caused by the minimum-stability flag as there is no stable release of the libraries on Packagist (existing releases don't support composer)

Christophe Coevoet

@claylo @sebastianbergmann the constraints should have an upper bound. Currently, phpunit/php-code-coverage says it is compatible with any phpunit/php-file-iterator release >=1.3.1. But you cannot ensure it as you don't know how all these releases will look like (a 2.0 version may break BC). As long as it is a branch, it is not an issue as you can update the requirements. But tagged releases cannot be updated as a tag cannot be modified.

And once you put an upper bound on constraints, you can use a branch alias for the master branch so that composer can know it is 1.4.x-dev or something like that.


:+1: finally!

Markus Bachmann

:+1: Awesome!
Thank you @claylo @sebastianbergmann

Peter Horne

Thanks @claylo and @sebastianbergmann. I've been looking forward to this!

Michi Lehr

Thank you guys for making this happen!

Sebastian Bergmann

@stof I'll gladly merge pull requests for the constraint issues you mention.

Luis Cordova

ya era hora!

Jordi Boggiano

Glad to see this moving forward. I tried it and found a few issues though, @claylo please take a look to double check: #647 #648 #649

Clay Loveless

@stof and @sebastianbergmann the upper-bound constraint issue is actually handled in the Package2XmlToComposer.php script.

If the PHPUnit* package.xml files begin supporting a max version value, subsequent runs of package2composer will pick those up. So, patch isn't necessary if PHPUnit team wants to start documenting max versions in their dependencies in package.xml.

@stof, regarding the extras section with branch aliasing, I will work out a way to support that -- probably by manually tweaking it in the package-composer.json config file.

Jon Peck fluxsauce referenced this pull request in myplanetdigital/vagrant-ariadne

Transition PHPUnit installation to leverage composer #54



Andreas Hoffmann

That is a very nice thing to happen :+1:
But I get a lot of "Cannot redeclare" errors on the "Generating autoloader files" step. The worst thing is that every time it seems to be another one.

"require": {
    "phpunit/phpunit": "3.7.*"

Currently its Cannot redeclare php_tokenstream_autoload() (previously declared in /var/lib/jenkins/workspace/project/vendor/phpunit/php-token-stream/PHP/Token/Stream/Autoload.php:45) in /var/lib/jenkins/workspace/project/vendor/phpunit/php-token-stream/PHP/Token/Stream/Autoload.php on line 230

I did't want to pollute #649 with this.

Michi Lehr

@Furizaa : run 'php composer.phar selfupdate', delete your vendor dir and run again 'php composer.phar install'

Clay Loveless

This is similar to giorgiosironi/phpunit-selenium#178

@Furizaa can you post your PHP version info? -- output of php --version? I'm curious if this is related to the Suhosin patch on OS X.

Andreas Hoffmann

Got the same problem on two boxes:

My development VBox

PHP 5.3.10-1ubuntu3.2 with Suhosin-Patch (cli) (built: Jun 13 2012 17:19:58) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
    with Xdebug v2.2.1, Copyright (c) 2002-2012, by Derick Rethans

and the Jenkins Bare-Metal

PHP 5.3.10-1ubuntu3.4 with Suhosin-Patch (cli) (built: Sep 12 2012 18:59:41) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans
    with Suhosin v0.9.33, Copyright (c) 2007-2012, by SektionEins GmbH
Clay Loveless

@Seldaek Can you have a look at this? In my experiments, changing Composer's autoload_real.php file to use require_once instead of require causes this problem to disappear.

It's notable that the problem people are describing only presents itself in installations with the Suhosin Patch. I'm working with a friend who knows the PHP internals well to help me attempt to track down the issue within the Suhosin patch, if any.

I'm going to try various combinations of specifying only the include paths and the main PHPUnit Autoload.php (and none of the sub-package files, since PHPUnit calls those), but in the event that this comes up again with other projects, I'd like to suggest considering require_once instead of require. Blasphemous, I know, but performance hit these days is negligible compared to the old days.

Andreas Hoffmann

Ok, @mickaelandrieu solution works on my dev box ... wich is awkward since my Jenkins build job fetches a fresh composer.phar from for every build without vendors installed.

Clay Loveless

@Furizaa interesting. Can you post the version string of the composer self-update that's working for you now?

Also, you might want to consider installing Composer globally on your Jenkins box so you can skip that download.

Andreas Hoffmann

So I learned today that apparently the version on isn't that version you get by a self-update :)

vagrant@precise64:/var/www$ php composer.phar self-update
Updating to version 6bd7ca0.

I've added the self-update command to my Jenkins job that is also working now.
That Jenkins has to fetch composer for every build is ok. I want to simulate a new developer fetching the repository to start working.

Jordi Boggiano

@claylo I already tried to explain that the way autoloading is done in the phpunit packages is broken, it would certainly work better with classmap or psr0 if phpunit was patched to not depend on its own specific autoloader - patch which I also provided, though granted it might not be complete. Anyway this might indeed work better with one of the latest versions of composer that prevents multiple includes of vendor/autoload.php from triggering many autoloaders. If that doesn't fix it, then I guess it should be fixed in phpunit.

Clay Loveless

@Seldaek I understand that you and Sebastian don't agree on how Autoloading should be done. What I'm suggesting is that it's possible that others who want to leverage Composer won't agree with you either. That'll probably be rare, but could happen.

Composer supports specifying a classmap file, or other "custom" includes. That's the whole point of the "file" option, right? To support composer installation for projects that don't adhere to classmaps or PSR-0? It would be smoother if everyone did do it that way, but the existence of 'file' autoload support indicates composer acknowledges and "works" with scenarios where packages do not do classmaps and PSR-0.

Right now, the issue that @Furizaa describes is still a problem on the default OS X 10.8.1 PHP, which is 5.3.13 with Suhosin Patch 0.9.10.

In my test autoload_real.php file, I currently see:

require $vendorDir . '/phpunit/php-file-iterator/File/Iterator/Autoload.php';
require $vendorDir . '/phpunit/php-text-template/Text/Template/Autoload.php';
require $vendorDir . '/phpunit/php-token-stream/PHP/Token/Stream/Autoload.php';
require $vendorDir . '/phpunit/php-code-coverage/PHP/CodeCoverage/Autoload.php';
require $vendorDir . '/phpunit/php-timer/PHP/Timer/Autoload.php';
require $vendorDir . '/phpunit/phpunit-mock-objects/PHPUnit/Framework/MockObject/Autoload.php';
require $vendorDir . '/phpunit/phpunit/PHPUnit/Autoload.php';
require $vendorDir . '/phpunit/phpunit-selenium/PHPUnit/Extensions/SeleniumCommon/Autoload.php';

With Suhosin Patch-free PHP 5.3.15, this works just fine. With Suhosin Patched 5.3.13, though, it results in:

Fatal error: Cannot redeclare phpunit_selenium_autoload() (previously declared in /Users/clay/issue178-composer-phar/vendor/phpunit/phpunit-selenium/PHPUnit/Extensions/SeleniumCommon/Autoload.php:47) in /Users/clay/issue178-composer-phar/vendor/phpunit/phpunit-selenium/PHPUnit/Extensions/SeleniumCommon/Autoload.php on line 117

Using require_once OR rearranging the order of the files in this list fixes this problem. Reason: PHPUnit/Autoload.php does a require_once on PHPUnit/Extensions/SeleniumCommon/Autoload.php.

Since autoload_real.php follows with a require, the "cannot redeclare" error occurs.

PHPUnit aside, there are other scenarios where this sort of thing could happen. Why not bypass them all by using require_once in autoload_real.php, or at least provide a flag in the "File" autoload type that allows edge-case packages to request require_once be used in their own files?

TL;DR: I don't think it's reasonable to assume that PHPUnit is the only project that will ever run into this issue. If you really want to drive adoption of Composer, I don't think "fix your project" is a scalable solution.

Andreas Hoffmann

@claylo I am able to reproduce this error. Hope this is helpful to you. OSX 10.8.0 with composer at HEAD.

➜  www-data git:(develop) php -v
PHP 5.3.13 with Suhosin-Patch (cli) (built: Jun 20 2012 17:05:20) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
➜  www-data git:(develop) php -i | grep Suhosin
This server is protected with the Suhosin Patch 0.9.10
Clay Loveless

thanks, @Furizaa. I've submitted pull requests on the PHPUnit family of packages that are already autoloaded BY PHPUnit. Once those changes are in place in those composer.json files, this issue should be resolved ... at least as far as PHPUnit is concerned.

Christophe Coevoet

@claylo with the latest version of Composer, the require statement should never be called several time as the method will return early when the autoloader was already initialized once.

@Furizaa which url are you using to fetch composer on your jenkins box ? The version on is the latest as this is where self-update is fetching it from

Clay Loveless

@stof the key word in your comment was "should" :)

What was happening is that PHPUnit's defined Autoload.php file was doing a require_once-if-present on optional dependencies, followed immediately by Composer doing a require on the same file.

I've fixed that in the case of the PHPUnit packages, but you won't know what others are going to do. Given that the computing overhead to use require_once is barely measurable compared to require, Composer is taking a stance on how things "should" be instead of supporting how things sometimes are.

A Google search on "tolerant on input, strict on output" brings up many, many additional voices suggesting that Composer's stance on require_once versus require is inverse of what it should be.

Jordi Boggiano


Composer supports specifying a classmap file, or other "custom" includes. That's the whole point of the "file" option, right? To support composer installation for projects that don't adhere to classmaps or PSR-0? It would be smoother if everyone did do it that way, but the existence of 'file' autoload support indicates composer acknowledges and "works" with scenarios where packages do not do classmaps and PSR-0.

  • Composer does not support specifying a classmap, it can generate the classmap from the php files you point it to if you use the "classmap" autoloading option.
  • "files" is mainly made to force-load functions since those can not be autoloaded. It shouldn't be abused since it means those files are required at every request, no matter if they're needed or not. Using it for a custom autoloader should not be needed since composer's autoloader can handle everything via either psr-0 or classmap.
  • PHPUnit's problem, and why I said it should be fixed in PHPUnit, is two-fold: it has its own autoloader that automatically loads the autoloaders of other packages (meaning the package is not self-contained and that's not good) and it requires its own autoloader (or at least part of it) for some functionality, which could (should IMO) be achieved differently, see my other PR that was closed.

Your solution of removing the files autoloading from the other packages so that stuff isn't loaded twice is not a great idea IMO because it means those packages can not be used standalone anymore, since they don't have an autoload config for composer.

Clay Loveless

@Seldaek This is all a matter of opinion, and your personal preferences are clear. So are Sebastian's. I guess what it really boils down to is whether or not Composer wants to be broadly adopted and tolerant of use cases or scenarios that don't perfectly fit your personal world view.

FWIW, the files I changed for the packages I adjusted have PHPUnit as a dependency, so they weren't being used standalone anyway.

Jordi Boggiano

It's not just a preference, the current way of doing it is wasting cpu cycles. If you choose not to care that's fine, but for such a high profile project as PHPUnit I think this sort of attention to detail is warranted.

Anyway I'll drop the case, this isn't going anywhere useful.

Sebastian Bergmann

Yes, the way that the autoloaders are implemented violates Separation of Concerns (because the class map is also used to populate the blacklist that is used to filter stack traces and code coverage information). I do not like this either. And I want to change it in the future. But I can not, and will not, rush this. I have other things in my life to do than to make Composer happy.

People can bitch about the PEAR Installer all they want: for me it always "just worked". There are only two benefits of using Composer that I see so far:

Composer makes it eas{ier|y} to maintain multiple versions of the same package. The lack for this was my only gripe with the PEAR Installer. Why this feature has been implemented in a new tool instead of improving the old tool is not for me to judge (I do not know the implementation details of the PEAR Installer).

The second benefit that I see is that Composer makes it eas{ier|y} to use development versions of packages by instrumenting Git. While this is not something that I missed personally so far, I do see the value of it.

Besides these two aforementioned benefits, I only see problems.

Jordi Boggiano

@sebastianbergmann glad to see you agree that it's not an ideal way, no problem with not rushing it, as I pointed out in my PR I wasn't sure it's a complete solution, and I realize you can't do major changes without some BC assurance. Anyway the current workaround works so no problem, it's just not perfect, but it'll do for most people. It's not about making composer happy, I just tried to point out the problem because I noticed it.

As for PEAR vs Composer, I hope we can agree on "to each his own". That said I'd be happy to hear what problems you see, maybe not here though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 129 additions and 0 deletions.
  1. +59 −0 composer.json
  2. +42 −0 composer/bin/phpunit
  3. +28 −0 package-composer.json
59 composer.json
@@ -0,0 +1,59 @@
+ "name": "phpunit/phpunit",
+ "description": "The PHP Unit Testing framework.",
+ "type": "library",
+ "keywords": [
+ "phpunit",
+ "xunit",
+ "testing"
+ ],
+ "homepage": "",
+ "license": "BSD-3-Clause",
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "",
+ "role": "lead"
+ }
+ ],
+ "version": "3.7.0RC5",
+ "time": "2012-09-17",
+ "support": {
+ "issues": "",
+ "irc": "irc://"
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-file-iterator": ">=1.3.1",
+ "phpunit/php-text-template": ">=1.1.1",
+ "phpunit/php-code-coverage": ">=1.2.0RC1",
+ "phpunit/php-timer": ">=1.0.2",
+ "phpunit/phpunit-mock-objects": ">=1.2.0RC1",
+ "symfony/yaml": ">=2.1.0RC1",
+ "ext-dom": "*",
+ "ext-pcre": "*",
+ "ext-reflection": "*",
+ "ext-spl": "*"
+ },
+ "suggest": {
+ "phpunit/php-invoker": ">=1.1.0",
+ "ext-json": "*",
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*"
+ },
+ "bin": [
+ "composer/bin/phpunit",
+ "phpunit.bat"
+ ],
+ "config": {
+ "bin-dir": "bin"
+ },
+ "autoload": {
+ "files": [
+ "PHPUnit/Autoload.php"
+ ]
+ },
+ "include-path": [
+ ""
+ ]
42 composer/bin/phpunit
@@ -0,0 +1,42 @@
+#!/usr/bin/env php
+/* PHPUnit
+ *
+ * Copyright (c) 2001-2012, Sebastian Bergmann <>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ */
+define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_Command::main');
+// pull in vendor/autoload.php as defined by composer
+require __DIR__ .'/../../../../autoload.php';
28 package-composer.json
@@ -0,0 +1,28 @@
+ "keywords": [ "phpunit", "xunit", "testing" ],
+ "license": "BSD-3-Clause",
+ "homepage": "",
+ "dependency_map": {
+ "": "phpunit/php-file-iterator",
+ "": "phpunit/php-text-template",
+ "": "phpunit/php-code-coverage",
+ "": "phpunit/php-timer",
+ "": "phpunit/phpunit-mock-objects",
+ "": "phpunit/php-invoker",
+ "": "symfony/yaml"
+ },
+ "support": {
+ "issues": "",
+ "irc": "irc://"
+ },
+ "autoload": {
+ "files": [ "PHPUnit/Autoload.php" ]
+ },
+ "include_path": [
+ ""
+ ],
+ "bin": [
+ "composer/bin/phpunit",
+ "phpunit.bat"
+ ]
Something went wrong with that request. Please try again.