This project aims to provide heavy-lifting refactoring and introspection tools which can be used standalone or as the backend for a text editor to provide intelligent code completion.
- No indexing: Composer is used to determine where things should be.
- Move and copy: Move and copy classes, updating PHP references to them.
- Class generation: Generate classes.
- Class inflection: Generate classes from other classes.
- Reflection API: Get reflection data for a given class or file.
- Type inference: Determine the type of something at a given offset.
- Transformation: Apply "transformations" to code (e.g. implement interfaces, add missing properties).
- Class search: Search for a class by its name.
- Class references: Find and replace references to class.
- Class method references: Find references to class methods.
- Autocompletion: Auto-completion command.
- VIM Plugin: see plugin README.
- Projects MUST use Composer and GIT.
- PHP 7.
Configuration files are loaded and merged from the current working directory and then by the XDG base dir standard.
To debug (and inspect) the configuration:
$ phpactor config:dump
Config files:
[-] /home/daniel/www/phpactor/phpactor/.phpactor.yml
[-] /home/daniel/.config/phpactor/phpactor.yml
[x] /etc/xdg/phpactor/phpactor.yml
autoload:vendor/autoload.php
cwd:/home/daniel/www/phpactor/phpactor
console_dumper_default:indented
reflector_stub_directory:/home/daniel/www/phpactor/phpactor/lib/Container/../../vendor/jetbrains/phpstorm-stubs
cache_dir:/home/daniel/www/phpactor/phpactor/lib/Container/../../cache
code_transform.indentation: " "
code_transform.class_new.variants:
- exception
- symfony_command
- phpunit_test
code_transform.template_paths:
- /home/daniel/www/phpactor/phpactor/.phpactor/templates
- Move classes: Move a class, or a glob of classes, to a new location and update all reference to it/them.
- Copy classes: As with move but copy to a new file.
- Class search: Search for a class by it's short name.
- Information at offset: Return the type information
- Reflect class: Return reflection data for a given class or file.
- Transform: Apply a transformation to a given file or from
STDIN.
- Implement Contracts: Implement interface/abstract methods.
- Complete Constructor: Finish off constructor definition.
All of the examples below will move the class and update all references in the source code to it.
Move the single class from one path to another:
$ phpactor class:move lib/Path/To/MyClass.php lib/NewLocation.php
Relocate all classes under Acme
to Foobar
:
$ phpactor class:move lib/Acme lib/Foobar
Relocate all classes in the lib
directory to a new subfolder:
$ phpactor class:move lib/* lib/Core
Move a class by name:
$ phpactor class:move "Acme\\BlogPost" "Acme\\Article"
- Moves individual class files or directories.
- Move by fully qualified class name of file path.
- Updates references for all moved classes in currently GIT tree.
- Use statements are updated or added when required.
Filesystem scope can be specified with --filesystem
.
As with move, except only update the class names of the copied class(es).
$ phpactor class:copy lib/Path/To/MyClass.php lib/Path/To/CopyOfMyClass.php
$ cat lib/Path/To/CopyOfMyClass.php | grep class
class CopyOfMyClass
Search for a class by its (short) name and return a list of fully qualified names => absolute paths.
$ phpactor class:search Filesystem
Phpactor\Filesystem\Domain\Filesystem:/.../vendor/phpactor/source-code-filesystem/lib/Domain/Filesystem.php
Symfony\Component\Filesystem\Filesystem:/.../vendor/symfony/filesystem/Filesystem.php
Also returns JSON with --format=json
and filesystem scope can be specified
with --filesystem
.
Find all references to a class:
$ phpactor references:class vendor/phpactor/worse-reflection/lib/Reflector.php
+------------------------------------+-----+-------------------------------------------------------+------+------+
| Path | LN | Line | OS | OE |
+------------------------------------+-----+-------------------------------------------------------+------+------+
| lib/Application/ClassReflector.php | 7 | use Phpactor\WorseReflection\Reflector; | 142 | 176 |
| lib/Application/ClassReflector.php | 32 | Reflector $reflector | 886 | 895 |
| lib/Application/Complete.php | 5 | use Phpactor\WorseReflection\Reflector; | 44 | 78 |
| lib/Application/Complete.php | 27 | public function __construct(Reflector $reflector) | 709 | 718 |
+------------------------------------+-----+-------------------------------------------------------+------+------+
Find and replace references to a class by specifying the --replace
option:
$ phpactor references:class vendor/phpactor/worse-reflection/lib/Reflector.php \
--replace="Phpactor\\AmazingReflection\\Refactor" \
--dry-run
# DRY RUN No files will be modified
# References:
+--------------------------------------------+-----+------------------------------------------------------------------------------------------------------------+------+------+
| Path | LN | Line | OS | OE |
+--------------------------------------------+-----+------------------------------------------------------------------------------------------------------------+------+------+
| lib/Application/ClassReflector.php | 7 | use Phpactor\WorseReflection\Reflector; | 142 | 176 |
| lib/Application/ClassReflector.php | 32 | Reflector $reflector | 886 | 895 |
| lib/Application/Complete.php | 5 | use Phpactor\WorseReflection\Reflector; | 44 | 78 |
| lib/Application/Complete.php | 27 | public function __construct(Reflector $reflector) | 709 | 718 |
+--------------------------------------------+-----+------------------------------------------------------------------------------------------------------------+------+------+
# Replacements:
+--------------------------------------------+-----+-----------------------------------------------------------------------------------------------------------+------+------+
| Path | LN | Line | OS | OE |
+--------------------------------------------+-----+-----------------------------------------------------------------------------------------------------------+------+------+
| lib/Application/ClassReflector.php | 7 | use Phpactor\AmazingReflection\Refactor; | 142 | 177 |
| lib/Application/ClassReflector.php | 32 | Refactor $reflector | 887 | 895 |
| lib/Application/Complete.php | 5 | use Phpactor\AmazingReflection\Refactor; | 44 | 79 |
| lib/Application/Complete.php | 27 | public function __construct(Refactor $reflector) | 710 | 718 |
+--------------------------------------------+-----+-----------------------------------------------------------------------------------------------------------+------+------+
4 reference(s)
The dry-run
option determines if files are modified or not.
Accepts either the class FQN or filename.
Also returns JSON with --format=json
and filesystem scope can be specified
with --filesystem
.
Find methods. When no options are provided all methods in the scope will be listed. If class is given, then all method calls on that class or any of its subclasses. If a method is given then only show calls to that method.
$ phpactor references:method --class="Symfony\\Component\\Console\\Input\\InputInterface"
# References:
+---------------------------------------------------------------+----+--------------------------------------------------------------------------------------------+------+------+
| Path | LN | Line | OS | OE |
+---------------------------------------------------------------+----+--------------------------------------------------------------------------------------------+------+------+
| lib/UserInterface/Console/Application.php | 54 | if ($input->⟶hasOption⟵('format') && $input->getOption('format')) { | 1775 | 1784 |
| lib/UserInterface/Console/Application.php | 54 | if ($input->hasOption('format') && $input->⟶getOption⟵('format')) { | 1806 | 1815 |
| lib/UserInterface/Console/Application.php | 55 | return $this->handleException($output, $input->⟶getOption⟵('format'), $e); | 1892 | 1901 |
| lib/UserInterface/Console/Command/ClassCopyCommand.php | 53 | $type = $input->⟶getOption⟵('type'); | 1562 | 1571 |
| lib/UserInterface/Console/Command/ClassCopyCommand.php | 55 | $src = $input->⟶getArgument⟵('src'); | 1661 | 1672 |
| lib/UserInterface/Console/Command/ClassCopyCommand.php | 56 | $dest = $input->⟶getArgument⟵('dest'); | 1705 | 1716 |
| lib/UserInterface/Console/Command/ClassInflectCommand.php | 53 | if ($input->⟶getOption⟵('list')) { | 1846 | 1855 |
| lib/UserInterface/Console/Command/ClassInflectCommand.php | 58 | $this->dumperRegistry->get($input->⟶getOption⟵('format'))->dump($output, $out); | 2028 | 2037 |
| ... | .. | | 2028 | 2037 |
+---------------------------------------------------------------+----+--------------------------------------------------------------------------------------------+------+------+
46 reference(s), 2 risky methods
Risky methods are method calls which match the given method name but the class
they are called on cannot be determined. They can be displayed using the
--risky
option.
Accepts either the class FQN or filename.
Also returns JSON with --format=json
and filesystem scope can be specified
with --filesystem
.
Return the fully qualified name of the class at the offset in the given file:
$ phpactor offset:info lib/Application/InformationForOffset/InformationForOffset.php 1382
type:Phpactor\ClassFileConverter\ClassName
path:/.../vendor/dtl/class-to-file/lib/ClassName.php
Also returns JSON with --format=json
Return reflection information for a given class name or file:
$ phpactor class:reflect lib/Application/Transformer.php
class:Phpactor\Application\Transformer
class_namespace:Phpactor\Application
class_name:Transformer
methods:
__construct:
name:__construct
abstract:
visibility:public
parameters:
transform:
name:transform
has_type:1
type:CodeTransform
has_default:
default:
static:0
type:<unknown>
synopsis:public function __construct(Phpactor\CodeTransform\CodeTransform $transform)
docblock:
transform:
# ...
Also returns JSON with --format=json
The transformation command accepts either a file name or stdin
and applies
the specified transformations.
$ phpactor class:transform lib/MyClass.php --transform=complete_constructor
Name: complete_constructor
This transformation will add any missing assignments in a constructor and add the class properties required.
In:
<?php
class Post
{
public function __construct(string $hello, Foobar $foobar)
{
}
}
Out:
<?php
class Post
{
/**
* @var string
*/
private $hello;
/**
* @var Foobar
*/
private $foobar;
public function __construct(string $hello, Foobar $foobar)
{
$this->hello = $hello;
$this->foobar = $foobar;
}
}
Name: implement_contracts
This transformer will implement any missing interface methods or abstract methods:
In:
<?php
class Post implements \Countable
{
}
Out:
<?php
class Post implements \Countable
{
/**
* {@inheritdoc}
*/
public function count()
{
}
}
Name: add_missing_assignments
This transformer will add any missing assignments from the current class as private properties.
In:
<?php
class Post
{
public function hello()
{
$this->mutate = new Turtle();
}
}
Out:
<?php
class Post
{
/**
* @var Turtle
*/
private $mutate;
public function hello()
{
$this->mutate = new Turtle();
}
}
Generates a new class at a given file path or class name:
$ phpactor class:new lib/Registry/Generator.php
path: lib/Registry/Generator.php
Different variants can be specified (contrived example):
$ phpactor class:new tests/Registry/GeneratorTest.php --variant=test
Variants are registered in .phpactor.yml
:
new_class_variants:
phpunit_test: phpunit_test
In order to create the above variant we need to create a template locally in
.phpactor/templates
(note you can also create them globally in the XDG
directories, in a templates
folder):
{# /path/to/project/.phpactor/templates/SourceCode.php.twig #}
namespace {{ prototype.namespace }};
use PHPUnit\Framework\TestCase;
{% for class in prototype.classes %}
class {{ class.name }} extends TestCase
{
}
{% endfor %}
Inflect a new class from an existing class.
The following will generate an interface from an existing class:
$ phpactor class:inflect lib/TestGenerator.php lib/Api/TestGenerator.php interface
This command will provide suggestions for the offset in a given file (or stdin). Currently
only ->
and ::
completions are supported.
$ phpactor complete lib/Application/Complete.php 983
suggestions:
0:
name:complete
info:pub complete(string $code, int $offset)
1:
name:getOffetToReflect
info:pri getOffetToReflect($code, $offset)
2:
name:getMethodInfo
info:pri getMethodInfo(ReflectionMethod $method)
3:
name:getPropertyInfo
info:pri getPropertyInfo(ReflectionProperty $property)
4:
name:reflector
info:pri $reflector
5:
name:filesystemHelper
info:pri $filesystemHelper
Also returns JSON with --format=json
- phpactor/class-mover: Find and update class references.
- phpactor/class-to-file: Convert files to class names and vice-versa.
- phpactor/code-builder: Library for creating and idempotently updating source code.
- phpactor/code-transform: Transform code.
- phpactor/source-code-filesystem: Find and manage source code files.
- phpactor/worse-reflection: Lightweight class reflection API
This project attempts to close the gap between text editors such as VIM and IDEs such as PHPStorm.
One of the interesting things about Phpactor is that it does not require any indexing before it is used. It leverages the Composer to determine class locations and to determine class FQNs from file locations. Introspection is done in realtime using Worse Reflection (which is based on the excellent Tolerant PHP Parser.
Using Composer we can locate a file using a fully qualified class name, when we have located the file we can parse it. This is enough for common auto-completion.
For other use cases, such as searching for a class, we simply perform a file search, but only in those directories mapped by Composer. Even in large projects searching for a class by its (short) name is pretty fast.
Follow @phpactor for the latest news.