__init_script__.php call another custom script


I have a strange behavior. When i start a script create in extension forlder, require_once $root.’/scripts/init_script.php’; line call another script in extension folder. And if i run these other script, the init_script run my first script.

  • folder structure :

debug command line :

D:\OutilsPHP\php\php-7.3.10-nts-Win32-VC15-x64\php.exe -dxdebug.remote_enable=1 -dxdebug.remote_mode=req -dxdebug.remote_port=9000 -dxdebug.remote_host= D:\OutilsPHP\Workspace\phabricator\Phabricator\src\extensions\mediaWikiMigration\import_mediawiki.php --config import-config.json --type allcat

  • import_mediawiki.php is running
  • debug point stop on line : require_once $root.’/scripts/init_script.php’;
  • I clic next, then run other conduit-test.script

D:\OutilsPHP\php\php-7.3.10-nts-Win32-VC15-x64\php.exe -dxdebug.remote_enable=1 -dxdebug.remote_mode=req -dxdebug.remote_port=9000 -dxdebug.remote_host= D:\OutilsPHP\Workspace\phabricator\Phabricator\src\extensions\test-conduit.php

the same but script test-conduit.php swith on import_mediawiki.php

test-conduit.php: (form Conduit : phriction.document.search OK or 444 or 501 randomly with same parameter)

#!/usr/bin/env php

$root = dirname(dirname(dirname(__FILE__)));
require_once $root.'/scripts/__init_script__.php';

$paths = array(

$api_parameters = array(
  'queryKey' => 'all',
  'constraints' => array(
    'paths' => $paths,
  'attachments' => array(
    'content' => true,


$root = dirname(dirname(dirname(dirname(__FILE__))));
require_once $root.'/scripts/__init_script__.php';

$args = new PhutilArgumentParser($argv);
$args->setTagline('Import MediaWikiService articles');
    **import_mediwiki.php** --config foo.json --type allcat [--action]

    Import MediaWikiService articles.
    Convert MW syntax to Remarkup.
    Create "category" pages with links to all imported articles.

        JSON config file with wiki.url, conduit.user, and conduit.api, ....

        MW category to import from (use "allcat" to retrieve all categories and linked-pages, "allpage" for all page, "cat" for all configured categories, "pages" for all configured pages)

        Action to perform (insert, replace - defaults to replace)

    __--help__: show this help



Sorry for all my stranges bugs and questions

At runtime, Phabricator must know which classes are available to load, and which classes they extend. This is because extensible behavior in Phabricator generally uses a pattern where Phabricator loads “all concrete classes which extend ancestor class X” to define runtime behavior.

For example, you can extend Phabricator’s search behavior by creating a class which extends PhabricatorSearchEngineExtension. At runtime, Phabricator introspects the class tree and loads all concrete descendants of PhabricatorSearchEngineExtension to make the extension actually work.

For formal libraries, Phabricator loads a library map file to figure out this information. This map file is generated with arc liberate and normally lives in src/__phutil_library_map__.php. The file is essentially a list of classes that the library defines mapped to the source files which define each class, plus a list of classes and interfaces that each class extends or implements.

With an ad-hoc library in extensions/, no map file exists. However, Phabricator still needs information about which classes are available to load, so it needs to get this information in some other way.

Phabricator could try to guess that a file named A.php probably contains a class named A, but this wouldn’t always be accurate, and does not give Phabricator any information about which classes A extends or which interfaces A implements.

Phabricator could run the same static analyzer that generates the library map on files in extensions/. However, while the analyzer is relatively fast as part of a developer workflow, it’s relatively slow as part of a web request. If we ran the static analyzer, putting even one file in extensions/ would make many Phabricator pages 2-3x slower. This also means the static analyzer needs to be available. It’s a C++ flex/bison parser, so this would add significant complexity to developing ad-hoc extensions.

Instead, Phabricator figures out which classes are available by loading every .php file inside extensions/ at startup. It then uses reflection to figure out which new classes were defined as a side effect, and then reflects those classes to figure out which other classes they extend and which interfaces they implement.

This approach also has limitations (for example, it is possible to define a class tree in extensions/ which Phabricator can not load, because it includes a subclass before a parent class and won’t know how to autoload the parent) but it’s very simple for ad-hoc developers, and extensions/ is intended to make it as easy as possible to accomplish very simple goals.

(One major use of extensions/ is that it makes it easy for me to say “put this file in extensions/” if a support customer has a problem which can be solved with an extension.)


  • Every “.php” file in extensions/ will always be loaded at runtime.
  • Do not put “.php” files which contain executable code at top level in extensions/. Instead, put them somewhere else. Phabricator puts files with top-level executable code in scripts/.
  • Generally, extensions/ is only suitable for very small/simple projects.
  • If your code calls Phabricator, but does not extend Phabricator, it does not need to live in extensions/ at all. I’m not sure exactly what you’re doing, but I would normally expect that an “import” script does not need to be an extension.
1 Like

Ok, i have a better understanding how phabricator work. Thanks.

I rewrited my script and use arc liberate, to create extension like a pro ;).
Migration script doesn’t need to be in extension but, that a way for me to search how work phabricator ans how can i work to extend phabricator.

Better like this :