How can I provide a script for PHP CLI via compose

2019-09-02 01:19发布

问题:

I am attempting to write a PHP script that I would like to run from the command line. I want to use composer to manage its dependencies, as well as to make it available to be installed as a dependency to other projects. I also want to maintain the ability to use it on its own (with its dependencies).

Currently, main.php is my "entry point" (what I would execute from the command line). As I built and tested it, I did so in the "stand alone" mindset. A such, main.php gets loads autoload like so:

<?php
require_once __DIR__.'/../vendor/autoload.php';

Continuing in stand alone mindset, I set it up like so:

  1. git clone package into place
  2. cd package
  3. composer install

This produces the following directory setup"

package
    |-composer.json
    |
    |-src
    |   |-ClassOne.php
    |   |
    |   |-ClassTwo.php
    |   |
    |   |-main.php
    |
    |-vendor
        |-autoload.php
        |
        |-composer
        |
        |-3rdpaty_1
        |
        |-3rdpaty_2

This works well--I can run php src/main.php which is able to find the classes it needs because it loads __DIR__.'../vendor/autoload.php'.

Where I run in to trouble is when I want to install the package as a dependency to another project (in order to have the script available to run there). I add my package to the composer.json and it gets installed. Attempting to run php vendor/compnay/package/src/main.php fails, however, because the necessary autoload.php is in a different place:

dependent_project
    |-composer.json
    |
    |-some_code
    |
    |-vendor
        |-autoload.php
        |
        |-composer
        |
        |-company
        |    |-package
        |        |-composer.json
        |        |
        |        |-src
        |            |-ClassOne.php
        |            |
        |            |-ClassTwo.php
        |            |
        |            |-main.php
        |
        |-other_vendor_1
        |
        |-other_vendor_2

I understand what is wrong, but I am not sure how to fix it. How does one provide such a thing using composer? I've searched around a lot but I don't see anyone asking or answering the same question. I notice the bin property of composer.json and started looking into that idea, but I'm still not finding a lot of info on how to properly set up my script to find what it needs in the different contexts.

I considered trying to use include in an if, and running a second include to the other path on fail, but that doesn't seem like the proper way to go about it.

回答1:

A common practice is to look into both locations for an autoload file. See for instance this snippet used by Behat:

function includeIfExists($file)
{
    if (file_exists($file)) {
        return include $file;
    }
}
if ((!$loader = includeIfExists(__DIR__.'/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../autoload.php'))) {
    fwrite(STDERR,
        'You must set up the project dependencies, run the following commands:'.PHP_EOL.
        'curl -s http://getcomposer.org/installer | php'.PHP_EOL.
        'php composer.phar install'.PHP_EOL
    );
    exit(1);
}