我正在为 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 有效,但对第二个则无效?
首先要明确的是namespaces、autoloading和Composer之间的关系。
CompanyName_GoogleTools_Sheet
这样的长名称。include
或 require
语句的一种方式,这样您就不必提前加载可能需要的每个类。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”包的依赖项,并安装它们,而无需您再次列出它们。