在我们的应用程序中使用PHP,检查一个包(任何版本)是否安装/存在的最干净的方法是什么?
基本上,在我们的应用程序中,我们希望调用一个具有以下签名的函数:bool function hasComposerPackage(string $packageName)
这个函数需要包含什么才能执行以下操作:
if (hasComposerPackage('phpunit/phpunit')) {
echo 'PHPUnit is installed!';
}
理想情况下,这需要在没有任何命令行exec调用的情况下进行,并且不应该在过程中自动加载任何 * 不必要的 * 文件。
3条答案
按热度按时间1szpjjfi1#
Composer 2(2020年10月)现在支持查找软件包安装状态!https://blog.packagist.com/composer-2-0-is-now-available/
有一个新的类Composer\InstalledVersions,它在每个项目中自动加载,并且在运行时可用。它允许您检查在您自己的项目运行时存在哪些包/版本。
以下用法示例来自 * 已安装版本- Runtime Composer实用程序 *:
@user1132363使用
shell_exec()
来运行类似composer show
的东西是唯一确定的方法(Composer低于2),但你似乎拒绝想走这条路。我不知道你为什么拒绝,这是你的问题的解决方案。没有其他可靠的方法。使用class_exists
也是不可靠的,因为类名称可以在包中更改。话虽如此,我认为还有一个更大的问题你没有问:你 * 实际上 * 试图解决什么问题?就像,为什么你需要检查一个包是否安装了?
lp0sw83n2#
这是一个老问题,我认为accepted answer是好的,但只是对于那些希望跨Composer版本移植的人,甚至可能在没有
composer
用户命令的系统上部署,并且还希望了解文件系统的底层协议。一般来说,您可以在安装 * 之后 * 从您自己的软件包中轻松获取供应商文件夹。
此外,在安装 * 其他 * Composer配置的软件包 * 之后,* 您同样可以轻松获取它们的安装状态。
像往常一样,我们可能“只”需要了解Composer本身如何与我们的(file-)系统,我在这里的回答中详细阐述了它,以突出您既不需要依赖于特定的Composer运行时版本,也不需要依赖于
shell_exec()
,因为我们已经在执行PHP代码,a)这是不必要的,B)我们可能没有composer(1)
(名为 composer 的用户命令),以及c)我们可能没有composer.json
的位置,也没有vendor
文件夹的位置。YMMV,对此我持保留态度,例如,如果我在构建时手头上有
composer(1)
,我就不会强调文件系统的细节,但是我可能已经从了解installed.json
文件中受益。让我们看看
vendor
文件夹到底是什么,它在哪里,以及包是如何放置在里面的,然后通过包名获取任何包的安装状态:vendor
。它相对于工作目录,默认情况下,composer将从该工作目录中的相对路径composer.json
加载项目配置(用于composer更新命令)和composer.lock
(用于composer安装命令,如果尚未禁用锁定文件)。1.可以更改这些设置,最突出的工作目录可能是
COMPOSER
环境参数的composer.json
(和.lock
),以及COMPOSER_VENDOR_DIR
参数的vendor目录。1.正如前面在问题中所讨论的,这些环境参数还会覆盖项目composer.json配置文件中的配置设置:主要是
#/config/vendor-dir
,但也包括具有或不具有锁定文件#/config/lock
的行为(#
之后的所有JSON指针相对于$COMPOSER_HOME/config.json
的JSON文本合并生成进行标记,并覆盖$COMPOSER
)。1.因此,如果您不想依赖运行时(例如,没有
shell_exec()
),则必须自己找出供应商目录。1.供应商目录只能在安装 * composer之后才能计算出来,如1.)中所述,它将创建 *vendor文件夹 *。
1.拥有一个由composer安装的软件包可以让你找到安装在 *vendor文件夹 * 中的文件。在PHP中,你可以通过
__DIR__
magic constant获取文件本身的路径。1.软件包在 *vendor文件夹 * 中的默认安装位置是 * 软件包名称 *。这也是为什么它应该全部小写并且只包含简化文件名字符集中的字符的原因:这样更便于移植,有助于您在 *vendor文件夹 * 中轻松查找软件包。
1.*vendor文件夹 * 中软件包的默认位置是
package-vendor-name/package-name-name
目录,每个软件包的默认位置是composer.json#/name
,例如,从 *vendor文件夹 **/*/composer.json#/name
的根目录开始。1.在您自己的代码中,您已经配置为与composer一起安装,并且您已经与composer一起安装了它,那么代码就可以从它自己的文件的
__DIR__
魔术常数中获得到 *vendor文件夹 * 的绝对路径,方法是获取层次结构中的祖父目录。例如,假设您的php文件在项目的根目录中,dirname(__DIR__, 2)
(或者dirname(dirname(dirname(__FILE__)))
,如果你需要这样的兼容性,对于7.0/5.3以下的PHP版本--Composers默认的自动加载器代码也支持它,顺便说一句,它与PHP 5.2兼容,所以在这个细节层次上,你 * 可能 * 想要支持它)。1.现在,在建立了 *vendor文件夹 * 的绝对路径之后,您可以通过文件夹查找其他软件包(与处理包和祖目录查找的方式相反),只需知道名称,-或-,通过定位
composer/installed.json
,它是composer install
命令调用的合成器标记文件,“*vendor文件夹”也安装了您的软件包。它的形式在历史上确实发生了变化,但变化不大。虽然我们已经走到了这一步,但这不应该是一个阻碍。安装(生成)时供应商文件夹中的非默认位置:
vendor文件夹仅仅是一个目录,并且在Composer安装之后,例如通过hook脚本或者仅仅因为你可以这样做,其中的文件可以自由地重新排列。
composer/installed.json
文件的好处是Composer本身保留了它在vendor文件夹中安装的协议。因此,尽管有些东西从默认位置移走了,但只要这个文件没有被移动,您通常就可以依赖它。Composer也是如此。在Composer用于安装(创建和填充vendor文件夹)的文件上,您可能并不总是看到更改的时间戳,因为它依赖于
composer/installed.json
文件来确定vendor文件夹的内容,并且如果它认为vendor文件夹生成已经完成,则不会更新。当您希望有一个干净的供应商文件夹生产时,您可以很容易地防止运行带有
--no-scripts
和--no-plugins
标志的composer命令的脚本,对于仅生产的供应商,可能使用--no-dev
。您可以轻松地基于
composer/installed.json
创建自己的供应商文件夹sentinel,方法是强制复制该文件夹,同时还将为您提供更新的时间戳。您可以通过在vendor文件夹中复制composer.json和composer.lock(如果正在使用)并设置
COMPOSER
环境参数来进一步创建sentinel。这样做的好处是,仍然可以对所有这些文件无效vendor文件夹,并获得额外的簿记。通常每个项目都是不同的,因此你可能只想从这个答案中挑选一个细节,甚至相反,你可能不想在你了解它 * 之后 * 使用它。只依赖
composer
的命令行界面并在之后拥有你的项目依赖项和自动加载器是相当有好处的。通过在
composer.json
中指定所需的包,您知道默认安装哪些包。Composer可以安装它们(您知道这些包在那里),也可以安装失败(您知道这些包不在那里)。hl0ma9xz3#
实际上你可以使用PHP的
class_exists()
函数。你只需要知道名称空间,我建议你把它作为一个字符串而不是ClassName::class
来使用。如果您使用的是composer自动加载,则返回true或false。