对类型库中包含的 COM 接口的 IntelliSense 支持

问题描述

对于 COM 类型库中包含的类型,有没有办法在 PHPStorm 中获得正常的 IntelliSense 功能

在 FoxPro 中,只要将变量声明为 COM 接口(它从注册表中提取信息),我就会获得完整的 IntelliSense;在 Delphi 和 Visual Studio 中,我可以让 IDE 为类型库(导入单元、互操作程序集)创建一些导入工件,以使 IntelliSense 工作。但是,到目前为止,我还没有找到让 IntelliSense 与 PHPStorm 中的类型库一起工作的方法

我发现所有提及的 COM 类型库仅指 PHP 加载常量 (com_load_typelib()) 的能力,但我想要方法和参数信息。我不介意从我的类型库中为 PHPStorm 生成文件,甚至不介意为我最常用的 COM 接口手工制作一些定义。但是,我真的需要 COM 接口的正常 IntelliSense 以防止发疯。

有没有办法给这只猫剥皮?

解决方法

正如 LazyOne 所建议的那样,手动方法可以像编写存根声明并将 php 文件转储到项目树或搜索路径中的某处(如适当的存根目录)一样简单:

<?php
/** allows observing the server lock/object counts and unloadability state of a COM module that uses the
 * Zrbj.COM.ComServerLocking infrastructure
 * @property-read int $Revision revision of the observer module implementation
 * @property-read string $ServerDLL executable which houses the code for this observer object
 */
interface ISrvDllObserver
{
    /** server lock count information (ICounterInfo) for this object's own server module */
    public function GetCountsForOwnModule (): ICounterInfo;

    /** server lock count information (ICounterInfo) for a loaded COM module that uses Zrbj.COM.ComServerLocking.
     * @param string $module_name basename without file extension is sufficient unless there are multiple loaded
     * modules with the same basename; use path and/or file extension to disambiguate
     */
    public function GetCountsForLoadedModule (string $module_name): ICounterInfo;
}

从那时起,IntelliSense 就可以完美运行。

手动过程可能会产生完美的结果,但非常费力。我记得 FoxPro 和早期版本的 Visual Studio 附带的用于处理类型库的脚本化对象 tlbinf32.dll (+ tlbinf32.chm)。开始的 ProgID 是 TLI.TLIApplication

我在 microsoft.com 上能找到的关于这个工具的唯一现存参考是这篇旧文章:

Visual Basic: Inspect COM Components Using the TypeLib Information Object Library

该工具仍随 Visual Studio 一起提供,但现在称为 vstlbinf.dll,不再记录。 vstlbinf.dll 仍将旧的 tlbinf32.chm 称为其帮助文件,但不再提供。旧文档对于理解对象模型仍然很有用,即使它指的是一个比 20 年前早的版本。 (注意:可能需要手动注册 DLL。)

所以我带着 Delphi 开始驯服 TLI.TLIApplication。事实证明,这并不比直接使用 ITypeLibITypeInfo 等容易很多,但优点是 TLI.TLIApplication 可以从任何脚本语言中使用,包括 PHP 本身。

以下是可以从 COM 类型库中提取以用于 PHP 存根的信息示例:

<?php
// 'k:\VS2019\Community\Common7\IDE\vstlbinf.dll' (2021-04-21 10:05:35)
// processed 2021-05-02 22:39:10 by Zrbj.COM.PhpStubs.pas rev. 2021-05-02
//
// Library: TLI
// Version: 1.0
// LIBID  : {8B217740-717D-11CE-AB5B-D41203C10000}
// Comment: TypeLib Information
// 32 interface(s) and 3 coclass(es)
//
// coclasses:
// * {8B217752-717D-11CE-AB5B-D41203C10000} -> _SearchHelper (ProgID TLI.SearchHelper)
//   'Helper object for GetMembersWithSubString and multiple TypeLibs'
// * {8B217746-717D-11CE-AB5B-D41203C10000} -> _TypeLibInfo (ProgID TLI.TypeLibInfo)
//   'TypeLib information'
// * {8B21775E-717D-11CE-AB5B-D41203C10000} -> _TLIApplication (ProgID TLI.TLIApplication)
//   'TLIApplication object'

/// {8B21774B-717D-11CE-AB5B-D41203C10000} dual nonextensible dispatchable
/** VarType information for parameters and return types
 * @property-read TypeInfo $TypeInfo Type information for VT_PTR VarType
 * @property-read int $TypeInfoNumber TypeInfo number for 0 VarType (Cheaper than TypeInfo property)
 * @property-read variant $TypedVariant Get a variant with this VarType
 * @property-read bool $IsExternalType Is TypeInfo external to this library
 * @property-read TypeLibInfo $TypeLibInfoExternal External typelib. Same as TypeInfo.Parent.
 * @property-read int $PointerLevel Dereferencing level of type
 * @property-read int $VarType VarType of Parameter
 * @property-read int $ElementPointerLevel Dereferencing level for type of an array element
 */
interface VarTypeInfo
{
    /** Get bounds for VT_VECTOR array. LBound in column 1,UBound in column 2. */
    public function ArrayBounds (int $Bounds): int;
}

/// {8B217749-717D-11CE-AB5B-D41203C10000} dual nonextensible dispatchable
/** Parameter Information
 * @property-read string $Name Name of the object
 * @property-read bool $Optional Optional Parameter
 * @property-read VarTypeInfo $VarTypeInfo VarTypeInfo object for this parameter
 * @property-read bool $Default Default Parameter
 * @property-read variant $DefaultValue Default value
 * @property-read bool $HasCustomData Check if custom data is available
 * @property-read CustomDataCollection $CustomDataCollection Custom data GUIDs and Values
 * @property-read int $Flags Parameter Flags
 */
interface ParameterInfo
{
}

...

明显缺少参数注释,因为在 Microsoft IDL 或类型库中没有这样的东西。但总的来说,将类型库处理成 PHP 存根的结果似乎还是比较令人满意的,而且它确实让 PHP 中的 COM 对象的处理变得更加容易。