xref: /plugin/pureldap/vendor/composer/InstalledVersions.php (revision fd0855eca89b78737f4256f2dab98af86002431b)
1*fd0855ecSAndreas Gohr<?php
2*fd0855ecSAndreas Gohr
3*fd0855ecSAndreas Gohr/*
4*fd0855ecSAndreas Gohr * This file is part of Composer.
5*fd0855ecSAndreas Gohr *
6*fd0855ecSAndreas Gohr * (c) Nils Adermann <naderman@naderman.de>
7*fd0855ecSAndreas Gohr *     Jordi Boggiano <j.boggiano@seld.be>
8*fd0855ecSAndreas Gohr *
9*fd0855ecSAndreas Gohr * For the full copyright and license information, please view the LICENSE
10*fd0855ecSAndreas Gohr * file that was distributed with this source code.
11*fd0855ecSAndreas Gohr */
12*fd0855ecSAndreas Gohr
13*fd0855ecSAndreas Gohrnamespace Composer;
14*fd0855ecSAndreas Gohr
15*fd0855ecSAndreas Gohruse Composer\Autoload\ClassLoader;
16*fd0855ecSAndreas Gohruse Composer\Semver\VersionParser;
17*fd0855ecSAndreas Gohr
18*fd0855ecSAndreas Gohr/**
19*fd0855ecSAndreas Gohr * This class is copied in every Composer installed project and available to all
20*fd0855ecSAndreas Gohr *
21*fd0855ecSAndreas Gohr * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22*fd0855ecSAndreas Gohr *
23*fd0855ecSAndreas Gohr * To require it's presence, you can require `composer-runtime-api ^2.0`
24*fd0855ecSAndreas Gohr */
25*fd0855ecSAndreas Gohrclass InstalledVersions
26*fd0855ecSAndreas Gohr{
27*fd0855ecSAndreas Gohr    private static $installed;
28*fd0855ecSAndreas Gohr    private static $canGetVendors;
29*fd0855ecSAndreas Gohr    private static $installedByVendor = array();
30*fd0855ecSAndreas Gohr
31*fd0855ecSAndreas Gohr    /**
32*fd0855ecSAndreas Gohr     * Returns a list of all package names which are present, either by being installed, replaced or provided
33*fd0855ecSAndreas Gohr     *
34*fd0855ecSAndreas Gohr     * @return string[]
35*fd0855ecSAndreas Gohr     * @psalm-return list<string>
36*fd0855ecSAndreas Gohr     */
37*fd0855ecSAndreas Gohr    public static function getInstalledPackages()
38*fd0855ecSAndreas Gohr    {
39*fd0855ecSAndreas Gohr        $packages = array();
40*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
41*fd0855ecSAndreas Gohr            $packages[] = array_keys($installed['versions']);
42*fd0855ecSAndreas Gohr        }
43*fd0855ecSAndreas Gohr
44*fd0855ecSAndreas Gohr        if (1 === \count($packages)) {
45*fd0855ecSAndreas Gohr            return $packages[0];
46*fd0855ecSAndreas Gohr        }
47*fd0855ecSAndreas Gohr
48*fd0855ecSAndreas Gohr        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
49*fd0855ecSAndreas Gohr    }
50*fd0855ecSAndreas Gohr
51*fd0855ecSAndreas Gohr    /**
52*fd0855ecSAndreas Gohr     * Returns a list of all package names with a specific type e.g. 'library'
53*fd0855ecSAndreas Gohr     *
54*fd0855ecSAndreas Gohr     * @param  string   $type
55*fd0855ecSAndreas Gohr     * @return string[]
56*fd0855ecSAndreas Gohr     * @psalm-return list<string>
57*fd0855ecSAndreas Gohr     */
58*fd0855ecSAndreas Gohr    public static function getInstalledPackagesByType($type)
59*fd0855ecSAndreas Gohr    {
60*fd0855ecSAndreas Gohr        $packagesByType = array();
61*fd0855ecSAndreas Gohr
62*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
63*fd0855ecSAndreas Gohr            foreach ($installed['versions'] as $name => $package) {
64*fd0855ecSAndreas Gohr                if (isset($package['type']) && $package['type'] === $type) {
65*fd0855ecSAndreas Gohr                    $packagesByType[] = $name;
66*fd0855ecSAndreas Gohr                }
67*fd0855ecSAndreas Gohr            }
68*fd0855ecSAndreas Gohr        }
69*fd0855ecSAndreas Gohr
70*fd0855ecSAndreas Gohr        return $packagesByType;
71*fd0855ecSAndreas Gohr    }
72*fd0855ecSAndreas Gohr
73*fd0855ecSAndreas Gohr    /**
74*fd0855ecSAndreas Gohr     * Checks whether the given package is installed
75*fd0855ecSAndreas Gohr     *
76*fd0855ecSAndreas Gohr     * This also returns true if the package name is provided or replaced by another package
77*fd0855ecSAndreas Gohr     *
78*fd0855ecSAndreas Gohr     * @param  string $packageName
79*fd0855ecSAndreas Gohr     * @param  bool   $includeDevRequirements
80*fd0855ecSAndreas Gohr     * @return bool
81*fd0855ecSAndreas Gohr     */
82*fd0855ecSAndreas Gohr    public static function isInstalled($packageName, $includeDevRequirements = true)
83*fd0855ecSAndreas Gohr    {
84*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
85*fd0855ecSAndreas Gohr            if (isset($installed['versions'][$packageName])) {
86*fd0855ecSAndreas Gohr                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
87*fd0855ecSAndreas Gohr            }
88*fd0855ecSAndreas Gohr        }
89*fd0855ecSAndreas Gohr
90*fd0855ecSAndreas Gohr        return false;
91*fd0855ecSAndreas Gohr    }
92*fd0855ecSAndreas Gohr
93*fd0855ecSAndreas Gohr    /**
94*fd0855ecSAndreas Gohr     * Checks whether the given package satisfies a version constraint
95*fd0855ecSAndreas Gohr     *
96*fd0855ecSAndreas Gohr     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
97*fd0855ecSAndreas Gohr     *
98*fd0855ecSAndreas Gohr     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
99*fd0855ecSAndreas Gohr     *
100*fd0855ecSAndreas Gohr     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
101*fd0855ecSAndreas Gohr     * @param  string        $packageName
102*fd0855ecSAndreas Gohr     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
103*fd0855ecSAndreas Gohr     * @return bool
104*fd0855ecSAndreas Gohr     */
105*fd0855ecSAndreas Gohr    public static function satisfies(VersionParser $parser, $packageName, $constraint)
106*fd0855ecSAndreas Gohr    {
107*fd0855ecSAndreas Gohr        $constraint = $parser->parseConstraints($constraint);
108*fd0855ecSAndreas Gohr        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
109*fd0855ecSAndreas Gohr
110*fd0855ecSAndreas Gohr        return $provided->matches($constraint);
111*fd0855ecSAndreas Gohr    }
112*fd0855ecSAndreas Gohr
113*fd0855ecSAndreas Gohr    /**
114*fd0855ecSAndreas Gohr     * Returns a version constraint representing all the range(s) which are installed for a given package
115*fd0855ecSAndreas Gohr     *
116*fd0855ecSAndreas Gohr     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
117*fd0855ecSAndreas Gohr     * whether a given version of a package is installed, and not just whether it exists
118*fd0855ecSAndreas Gohr     *
119*fd0855ecSAndreas Gohr     * @param  string $packageName
120*fd0855ecSAndreas Gohr     * @return string Version constraint usable with composer/semver
121*fd0855ecSAndreas Gohr     */
122*fd0855ecSAndreas Gohr    public static function getVersionRanges($packageName)
123*fd0855ecSAndreas Gohr    {
124*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
125*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
126*fd0855ecSAndreas Gohr                continue;
127*fd0855ecSAndreas Gohr            }
128*fd0855ecSAndreas Gohr
129*fd0855ecSAndreas Gohr            $ranges = array();
130*fd0855ecSAndreas Gohr            if (isset($installed['versions'][$packageName]['pretty_version'])) {
131*fd0855ecSAndreas Gohr                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
132*fd0855ecSAndreas Gohr            }
133*fd0855ecSAndreas Gohr            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
134*fd0855ecSAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
135*fd0855ecSAndreas Gohr            }
136*fd0855ecSAndreas Gohr            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
137*fd0855ecSAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
138*fd0855ecSAndreas Gohr            }
139*fd0855ecSAndreas Gohr            if (array_key_exists('provided', $installed['versions'][$packageName])) {
140*fd0855ecSAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
141*fd0855ecSAndreas Gohr            }
142*fd0855ecSAndreas Gohr
143*fd0855ecSAndreas Gohr            return implode(' || ', $ranges);
144*fd0855ecSAndreas Gohr        }
145*fd0855ecSAndreas Gohr
146*fd0855ecSAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
147*fd0855ecSAndreas Gohr    }
148*fd0855ecSAndreas Gohr
149*fd0855ecSAndreas Gohr    /**
150*fd0855ecSAndreas Gohr     * @param  string      $packageName
151*fd0855ecSAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
152*fd0855ecSAndreas Gohr     */
153*fd0855ecSAndreas Gohr    public static function getVersion($packageName)
154*fd0855ecSAndreas Gohr    {
155*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
156*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
157*fd0855ecSAndreas Gohr                continue;
158*fd0855ecSAndreas Gohr            }
159*fd0855ecSAndreas Gohr
160*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName]['version'])) {
161*fd0855ecSAndreas Gohr                return null;
162*fd0855ecSAndreas Gohr            }
163*fd0855ecSAndreas Gohr
164*fd0855ecSAndreas Gohr            return $installed['versions'][$packageName]['version'];
165*fd0855ecSAndreas Gohr        }
166*fd0855ecSAndreas Gohr
167*fd0855ecSAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
168*fd0855ecSAndreas Gohr    }
169*fd0855ecSAndreas Gohr
170*fd0855ecSAndreas Gohr    /**
171*fd0855ecSAndreas Gohr     * @param  string      $packageName
172*fd0855ecSAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
173*fd0855ecSAndreas Gohr     */
174*fd0855ecSAndreas Gohr    public static function getPrettyVersion($packageName)
175*fd0855ecSAndreas Gohr    {
176*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
177*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
178*fd0855ecSAndreas Gohr                continue;
179*fd0855ecSAndreas Gohr            }
180*fd0855ecSAndreas Gohr
181*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
182*fd0855ecSAndreas Gohr                return null;
183*fd0855ecSAndreas Gohr            }
184*fd0855ecSAndreas Gohr
185*fd0855ecSAndreas Gohr            return $installed['versions'][$packageName]['pretty_version'];
186*fd0855ecSAndreas Gohr        }
187*fd0855ecSAndreas Gohr
188*fd0855ecSAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
189*fd0855ecSAndreas Gohr    }
190*fd0855ecSAndreas Gohr
191*fd0855ecSAndreas Gohr    /**
192*fd0855ecSAndreas Gohr     * @param  string      $packageName
193*fd0855ecSAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
194*fd0855ecSAndreas Gohr     */
195*fd0855ecSAndreas Gohr    public static function getReference($packageName)
196*fd0855ecSAndreas Gohr    {
197*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
198*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
199*fd0855ecSAndreas Gohr                continue;
200*fd0855ecSAndreas Gohr            }
201*fd0855ecSAndreas Gohr
202*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName]['reference'])) {
203*fd0855ecSAndreas Gohr                return null;
204*fd0855ecSAndreas Gohr            }
205*fd0855ecSAndreas Gohr
206*fd0855ecSAndreas Gohr            return $installed['versions'][$packageName]['reference'];
207*fd0855ecSAndreas Gohr        }
208*fd0855ecSAndreas Gohr
209*fd0855ecSAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
210*fd0855ecSAndreas Gohr    }
211*fd0855ecSAndreas Gohr
212*fd0855ecSAndreas Gohr    /**
213*fd0855ecSAndreas Gohr     * @param  string      $packageName
214*fd0855ecSAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
215*fd0855ecSAndreas Gohr     */
216*fd0855ecSAndreas Gohr    public static function getInstallPath($packageName)
217*fd0855ecSAndreas Gohr    {
218*fd0855ecSAndreas Gohr        foreach (self::getInstalled() as $installed) {
219*fd0855ecSAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
220*fd0855ecSAndreas Gohr                continue;
221*fd0855ecSAndreas Gohr            }
222*fd0855ecSAndreas Gohr
223*fd0855ecSAndreas Gohr            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
224*fd0855ecSAndreas Gohr        }
225*fd0855ecSAndreas Gohr
226*fd0855ecSAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
227*fd0855ecSAndreas Gohr    }
228*fd0855ecSAndreas Gohr
229*fd0855ecSAndreas Gohr    /**
230*fd0855ecSAndreas Gohr     * @return array
231*fd0855ecSAndreas Gohr     * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
232*fd0855ecSAndreas Gohr     */
233*fd0855ecSAndreas Gohr    public static function getRootPackage()
234*fd0855ecSAndreas Gohr    {
235*fd0855ecSAndreas Gohr        $installed = self::getInstalled();
236*fd0855ecSAndreas Gohr
237*fd0855ecSAndreas Gohr        return $installed[0]['root'];
238*fd0855ecSAndreas Gohr    }
239*fd0855ecSAndreas Gohr
240*fd0855ecSAndreas Gohr    /**
241*fd0855ecSAndreas Gohr     * Returns the raw installed.php data for custom implementations
242*fd0855ecSAndreas Gohr     *
243*fd0855ecSAndreas Gohr     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
244*fd0855ecSAndreas Gohr     * @return array[]
245*fd0855ecSAndreas Gohr     * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
246*fd0855ecSAndreas Gohr     */
247*fd0855ecSAndreas Gohr    public static function getRawData()
248*fd0855ecSAndreas Gohr    {
249*fd0855ecSAndreas Gohr        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
250*fd0855ecSAndreas Gohr
251*fd0855ecSAndreas Gohr        if (null === self::$installed) {
252*fd0855ecSAndreas Gohr            // only require the installed.php file if this file is loaded from its dumped location,
253*fd0855ecSAndreas Gohr            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
254*fd0855ecSAndreas Gohr            if (substr(__DIR__, -8, 1) !== 'C') {
255*fd0855ecSAndreas Gohr                self::$installed = include __DIR__ . '/installed.php';
256*fd0855ecSAndreas Gohr            } else {
257*fd0855ecSAndreas Gohr                self::$installed = array();
258*fd0855ecSAndreas Gohr            }
259*fd0855ecSAndreas Gohr        }
260*fd0855ecSAndreas Gohr
261*fd0855ecSAndreas Gohr        return self::$installed;
262*fd0855ecSAndreas Gohr    }
263*fd0855ecSAndreas Gohr
264*fd0855ecSAndreas Gohr    /**
265*fd0855ecSAndreas Gohr     * Returns the raw data of all installed.php which are currently loaded for custom implementations
266*fd0855ecSAndreas Gohr     *
267*fd0855ecSAndreas Gohr     * @return array[]
268*fd0855ecSAndreas Gohr     * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
269*fd0855ecSAndreas Gohr     */
270*fd0855ecSAndreas Gohr    public static function getAllRawData()
271*fd0855ecSAndreas Gohr    {
272*fd0855ecSAndreas Gohr        return self::getInstalled();
273*fd0855ecSAndreas Gohr    }
274*fd0855ecSAndreas Gohr
275*fd0855ecSAndreas Gohr    /**
276*fd0855ecSAndreas Gohr     * Lets you reload the static array from another file
277*fd0855ecSAndreas Gohr     *
278*fd0855ecSAndreas Gohr     * This is only useful for complex integrations in which a project needs to use
279*fd0855ecSAndreas Gohr     * this class but then also needs to execute another project's autoloader in process,
280*fd0855ecSAndreas Gohr     * and wants to ensure both projects have access to their version of installed.php.
281*fd0855ecSAndreas Gohr     *
282*fd0855ecSAndreas Gohr     * A typical case would be PHPUnit, where it would need to make sure it reads all
283*fd0855ecSAndreas Gohr     * the data it needs from this class, then call reload() with
284*fd0855ecSAndreas Gohr     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
285*fd0855ecSAndreas Gohr     * the project in which it runs can then also use this class safely, without
286*fd0855ecSAndreas Gohr     * interference between PHPUnit's dependencies and the project's dependencies.
287*fd0855ecSAndreas Gohr     *
288*fd0855ecSAndreas Gohr     * @param  array[] $data A vendor/composer/installed.php data set
289*fd0855ecSAndreas Gohr     * @return void
290*fd0855ecSAndreas Gohr     *
291*fd0855ecSAndreas Gohr     * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
292*fd0855ecSAndreas Gohr     */
293*fd0855ecSAndreas Gohr    public static function reload($data)
294*fd0855ecSAndreas Gohr    {
295*fd0855ecSAndreas Gohr        self::$installed = $data;
296*fd0855ecSAndreas Gohr        self::$installedByVendor = array();
297*fd0855ecSAndreas Gohr    }
298*fd0855ecSAndreas Gohr
299*fd0855ecSAndreas Gohr    /**
300*fd0855ecSAndreas Gohr     * @return array[]
301*fd0855ecSAndreas Gohr     * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
302*fd0855ecSAndreas Gohr     */
303*fd0855ecSAndreas Gohr    private static function getInstalled()
304*fd0855ecSAndreas Gohr    {
305*fd0855ecSAndreas Gohr        if (null === self::$canGetVendors) {
306*fd0855ecSAndreas Gohr            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
307*fd0855ecSAndreas Gohr        }
308*fd0855ecSAndreas Gohr
309*fd0855ecSAndreas Gohr        $installed = array();
310*fd0855ecSAndreas Gohr
311*fd0855ecSAndreas Gohr        if (self::$canGetVendors) {
312*fd0855ecSAndreas Gohr            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
313*fd0855ecSAndreas Gohr                if (isset(self::$installedByVendor[$vendorDir])) {
314*fd0855ecSAndreas Gohr                    $installed[] = self::$installedByVendor[$vendorDir];
315*fd0855ecSAndreas Gohr                } elseif (is_file($vendorDir.'/composer/installed.php')) {
316*fd0855ecSAndreas Gohr                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
317*fd0855ecSAndreas Gohr                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
318*fd0855ecSAndreas Gohr                        self::$installed = $installed[count($installed) - 1];
319*fd0855ecSAndreas Gohr                    }
320*fd0855ecSAndreas Gohr                }
321*fd0855ecSAndreas Gohr            }
322*fd0855ecSAndreas Gohr        }
323*fd0855ecSAndreas Gohr
324*fd0855ecSAndreas Gohr        if (null === self::$installed) {
325*fd0855ecSAndreas Gohr            // only require the installed.php file if this file is loaded from its dumped location,
326*fd0855ecSAndreas Gohr            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
327*fd0855ecSAndreas Gohr            if (substr(__DIR__, -8, 1) !== 'C') {
328*fd0855ecSAndreas Gohr                self::$installed = require __DIR__ . '/installed.php';
329*fd0855ecSAndreas Gohr            } else {
330*fd0855ecSAndreas Gohr                self::$installed = array();
331*fd0855ecSAndreas Gohr            }
332*fd0855ecSAndreas Gohr        }
333*fd0855ecSAndreas Gohr        $installed[] = self::$installed;
334*fd0855ecSAndreas Gohr
335*fd0855ecSAndreas Gohr        return $installed;
336*fd0855ecSAndreas Gohr    }
337*fd0855ecSAndreas Gohr}
338