duanbi3151 2015-06-21 07:30
浏览 46
已采纳

PHP Autoloader不适用于Ubuntu生产服务器

I have to environments i'm working developing my API (PHP based):

  1. Local development: Mac OS Yosemite - running PHP 5.5.20
  2. Production server: Ubuntu server - running PHP 5.5.9

My code uses composer for auto loading as followed:

{
    "require": {
        "facebook/php-sdk": "@stable",
        "everyman/neo4jphp": "dev-master",
        "predis/predis": "1.0.1",
        "aws/aws-sdk-php": "2.*"
    },

    "autoload": {
        "psr-0": {
            "PicoCore\\": "",
            "PicoCore\\Authentication\\" : "PicoCore/authentication",
            "PicoCore\\Aws\\" : "PicoCore/aws",
            "PicoCore\\Cache\\" : "PicoCore/cache",
            "PicoCore\\Database\\" : "PicoCore/database",
            "PicoCore\\Database\\Managers\\" : "PicoCore/database/managers",
            "PicoCore\\Facebook\\" : "PicoCore/facebook",
            "PicoCore\\Objects\\" : "PicoCore/objects",
            "PicoCore\\Rest\\" : "PicoCore/rest",
            "PicoCore\\Configuration\\" : "PicoCore/configuration",
            "PicoCore\\Configuration\\Api\\" : "PicoCore/configuration/api",
            "PicoCore\\Configuration\\PictureReceiver\\" : "PicoCore/configuration/pictureReceiver",
            "PicoCore\\Configuration\\PictureUploader\\" : "PicoCore/configuration/pictureUploader",
            "PicoCore\\Scripts\\" : "PicoCore/scripts",
            "PicoCore\\Times" : "PicoCore/times"
        }
    }
}

This is my loading function:

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'PicoCore\\Times' => array($baseDir . '/PicoCore/times'),
    'PicoCore\\Scripts\\' => array($baseDir . '/PicoCore/scripts'),
    'PicoCore\\Rest\\' => array($baseDir . '/PicoCore/rest'),
    'PicoCore\\Objects\\' => array($baseDir . '/PicoCore/objects'),
    'PicoCore\\Facebook\\' => array($baseDir . '/PicoCore/facebook'),
    'PicoCore\\Database\\Managers\\' => array($baseDir . '/PicoCore/database/managers'),
    'PicoCore\\Database\\' => array($baseDir . '/PicoCore/database'),
    'PicoCore\\Configuration\\PictureUploader\\' => array($baseDir . '/PicoCore/configuration/pictureUploader'),
    'PicoCore\\Configuration\\PictureReceiver\\' => array($baseDir . '/PicoCore/configuration/pictureReceiver'),
    'PicoCore\\Configuration\\Api\\' => array($baseDir . '/PicoCore/configuration/api'),
    'PicoCore\\Configuration\\' => array($baseDir . '/PicoCore/configuration'),
    'PicoCore\\Cache\\' => array($baseDir . '/PicoCore/cache'),
    'PicoCore\\Aws\\' => array($baseDir . '/PicoCore/aws'),
    'PicoCore\\Authentication\\' => array($baseDir . '/PicoCore/authentication'),
    'PicoCore\\' => array($baseDir . '/'),
    'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'),
    'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'),
    'Everyman\\Neo4j' => array($vendorDir . '/everyman/neo4jphp/lib'),
    'Aws' => array($vendorDir . '/aws/aws-sdk-php/src'),
);

When i'm running my code on my local development - it works perfectly, so I pushed it to my remote repository and pull it from the production server.

When i'm trying to run my code in my Production server I receive a Class not found error indicating that my autoloading didn't run properly.

Any ideas what could be the reason ?

UPDATE: When i'm trying to load the external libs (like AWS) it does work, so the problem is defiantly something with how my folders are being loaded.

UPDATE: This is the class i'm trying to load from index.php:

<?php
//require Pico Core autoload
require 'core/vendor/autoload.php';

//require Pico Api autoload
require 'vendor/autoload.php';

use PicoCore\Rest\ApiInitializer;
use PicoCore\Configuration\Error;
use PicoApi\Managers\ApiManager;

try {
    //initialize the API
    ApiInitializer::initialize();
    //initialize a new Api with the request
    $api = new ApiManager($_REQUEST['request']);
    echo utf8_encode($api->processApi());

} catch (Exception $e) {
    echo json_encode(Array(Error::jsonErrorField() => $e->getMessage()));
}

This is the error I receive Class 'PicoCore\Rest\ApiInitializer' not found

The structure is:

api
 |
 core
   |
   PicoCore
      |
     folders..
     rest
      |
      ApiInitializer.php
     folders...
    vender
 PicoApi (folder)
 vendor (foldeR)
 index.php
  • 写回答

1条回答 默认 最新

  • douzhou7037 2015-06-21 21:09
    关注

    It's your wrong autoloading definition.

    You want to use the class

    PicoCore\Rest\ApiInitializer
    

    And you have these files:

    api/index.php
    api/vendor/...    (with your required external dependencies)
    api/composer.json (with the autoloading mentioned in your question)
    api/core/PicoCore/rest/ApiInitializer.php
    

    And you have this autoloading configured:

    "autoload": { "psr-0": { "PicoCore\Rest\" : "PicoCore/rest" } }

    This is a mismatch. When you use the class PicoCore\Rest\ApiInitializer, composer will try to locate an entry with a prefix of that class. It will sucessfully detect that classes with prefix PicoCode\Rest can be found via PSR-0 rules in the directory (relative to the position of composer.json) PicoCore/rest.

    First strange thing: There is an additional directory named "core" here, and you seem to include TWO autoloaders. Don't do that, Composer works best with only one autoloader.

    Second thing: If I ignore that "core" directory for a bit, the PSR-0 rules state that the classname will be converted to a path - and then be searched in the path given for the prefix.

    PicoCore\Rest\ApiInitializer as a path is PicoCore/Rest/ApiInitializer.php (note the uppercase "R" in "Rest"), and the path this is to be found is PicoCore/rest/PicoCore/Rest/ApiInitializer.php.

    You don't have this file. And thats why Composer cannot find and load it. And this is even without counting this "core" directory level, it will also not be found if you used two composer.json files, one in api and one in api/core, and the one in api/core was used to find the class.

    Suggestions:

    1. Use PSR-4 for every class that is inside a namespace.
    2. Don't lowercase namespace or classname parts for the filesystem.
    3. Shorten your autoloading definition. If you'd rename all those lowercase directories below PicoCore into the proper uppercase variants that are being used in your namespace, you will only need one line of autoloading definition, defining the PicoCore prefix. The rest is done by PSR-4 (or PSR-0).

    MacOS is using a case insensitive file system by default, and it is considered a bad thing to switch it to case sensitive: https://apple.stackexchange.com/questions/71357/how-to-check-if-my-hd-is-case-sensitive-or-not That's why it is working on Mac, but not Linux.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?