当从另一个地方使用本地包时,Composer 不会自动加载类

问题描述 投票:0回答:1

我正在为 Google API 创建一个包装器包,我只想在本地使用它,并且我希望通过命名空间而不是本地存储库将其包含在具有 Composer 的其他本地项目中。

尝试在测试项目中使用它会导致

PHP Fatal error:  Uncaught Error: Class "Google_Client" not found.
但它在原始包中工作正常。

我这个工作正常,然后我不知道发生了什么变化,现在它不起作用。

我做了一个干净的测试来演示这个问题:

├── companyname
│   └── googletools
│       ├── bin
│       ├── composer.json
│       ├── composer.lock
│       ├── config
│       ├── src
│       └── vendor
└── testproject
    ├── bin
    │   └── test.php
    ├── composer.json
    ├── composer.lock
    ├── src
    └── vendor
        ├── autoload.php
        └── composer

googletools/composer.json 是:

{
    "name": "companyname/googletools",
    "version": "1.0.0",
    "require": {
        "google/apiclient": "^2.17"
    },
    "autoload": {
        "psr-4": {
            "CompanyName\\GoogleTools\\": "src/"
        }
    }
}

testproject/composer.json 是

{
    "name": "companyname/testproject",
    "version": "1.0.0",
    "require": {
    },
    "autoload": {
        "psr-4": {
            "Testproject\\": "src/",
            "CompanyName\\GoogleTools\\": "../companyname/googletools/src"
        }
    }
}

googletools/bin/test.php 是:

<?php

require __DIR__.'/../vendor/autoload.php';

$sheetId = 'mysheetid;

$sheet = new CompanyName\GoogleTools\Sheet($sheetId);

$sheetName = 'mysheetname';

$range = $sheetName;

$response = $sheet->spreadsheets_values->get($sheetId, $range);
$values = $response->getValues();

print_r($values);

上面的 test.php 工作正常,输出符合预期。

testproject/bin/test.php 是:

<?php

require __DIR__.'/../vendor/autoload.php';

use CompanyName\GoogleTools\Sheet;

$sheetId = 'mysheetid;

$sheet = new CompanyName\GoogleTools\Sheet($sheetId);

$sheetName = 'mysheetname';

$range = $sheetName;

$response = $sheet->spreadsheets_values->get($sheetId, $range);
$values = $response->getValues();

print_r($values);

输出是:

PHP Fatal error:  Uncaught Error: Class "Google_Client" not found in /Path/to/companyname/googletools/src/Sheet.php:22

Sheet.php 开始:

<?php

namespace CompanyName\GoogleTools;

use Google_Client;
use Google_Service_Sheets;

为什么这对第一个 test.php 有效,但对第二个则无效?

php composer-php
1个回答
0
投票

首先要明确的是namespacesautoloadingComposer之间的关系。

  • A namespace 基本上是一种确保一个库中的类名不会与另一个库中的名称冲突的方法,而不必连续编写像
    CompanyName_GoogleTools_Sheet
    这样的长名称。
  • 自动加载基本上是告诉 PHP 加载类定义需要什么
    include
    require
    语句的一种方式,这样您就不必提前加载可能需要的每个类。
  • Composer 主要是一种指定要安装的软件包列表、解析其所有依赖项并下载它们的方法。由于它知道文件安装在哪里,因此它可以为它们设置自动加载器功能。这就是您使用行
    require __DIR__.'/../vendor/autoload.php';
  • 激活的内容

那么,让我们看看您的示例中发生了什么:

  • use Google_Client;
    与命名空间有关;它只是一个编译器指令,表示“在这个文件中,如果我提到
    Google_Client
    ,我的意思是
    \Google_Client
    ”。它不会触发任何自动加载。
  • 稍后,您可能会运行
    new Google_Client
    或类似的命令。这触发自动加载。
  • 当您运行
    companyname/googletools/bin/test.php
    时,您加载的自动加载器是
    companyname/googletools/vendor/autoload.php
    中的自动加载器,它基于
    companyname/googletools/composer.json
    。它知道它已将
    google/api-client
    安装到目录
    companyname/googletools/vendor/google/api-client
    中。它还知道该包包含类
    Google_Client
    ,因此会为您加载它。
  • 当您运行
    testproject/bin/test.php
    时,您加载的自动加载器是
    testproject/vendor/autoload.php
    中的自动加载器,基于
    testproject/composer.json
    。目前知道以
    Testproject\
    开头的类在
    src/
    中,以
    CompanyName\GoogleTools
    开头的类在
    companyname/googletools/
    中,但它还没有在
    testproject/vendor
    中安装任何东西(除了 Composer 的内部机制)。它不知道任何包含类
    Google_Client
    的文件。

最简单的解决方案是在

google/api-client
requires
部分列出
testproject/composer.json
。这样,Composer 将在
testproject/vendor/google/api-client
中安装一个副本,并能够为您自动加载它。

更复杂但更强大的解决方案是将您的“googletools”库设置为私有Composer包,然后在requires列表中列出

testproject/composer.json
。这样,Composer 将查看“googletools”包的依赖项,并安装它们,而无需您再次列出它们。
    

© www.soinside.com 2019 - 2024. All rights reserved.