Memio provides a way to describe Models (classes, properties, methods, etc). Here's a cheat sheet of those:
In this tutorial, we'll see how to:
- Generate a chunk of code (e.g. a single argument)
- Generate a standalone collection (e.g. many arguments)
- Generate a collection in a Model (e.g. method's arguments)
- Example: phpspec's method generation
- Generate multiline arguments (e.g. PSR-2 compliant)
- Generate visibility, staticness, virtualness, etc...
- Generate Constant and default values
- Generate Class and Interface
- Generate File
The code sample in the README demonstrates how to generate a complete file. But it is also possible to only generate a chunk of code, like a method's argument.
We can describe it by providing the type and the name:
use Memio\Model\Argument;
$filename = new Argument('string', 'filename');
echo $prettyPrinter->generateCode($filename);
Note: the following types are accepted: string, bool, int, double, callable, resource, array, null, mixed. If something else is given, Memio will consider it as an object.
This should print the following:
$filename
Memio is able to automatically type hint an argument, when necessary:
$createdAt = new Argument('DateTime', 'createdAt');
echo $prettyPrinter->generateCode($createdAt);
This will result in:
DateTime $createdAt
Note: The following types are type hinted: object, array and callable (only if Memio is ran using PHP >= 5.4).
An argument on its own is not very usefull, usually methods have a collection of arguments (0 to many). This can be done by using arrays:
$handleArguments = array(
new Argument('Symfony\Component\HttpFoundation\Request', 'request'),
Argument::make('int', 'type')
->setDefaultValue('self::MASTER_REQUEST')
,
Argument::make('bool', 'catch')
->setDefaultValue('true')
,
);
echo $prettyPrinter->generateCode($handleArguments);
Note: All models can either be instanciated using
new
or the static methodmake
. The second option enable "fluent interface" (chaining method calls), when using PHP 5.4 this becomes unnecessary as we can use(new Argument('bool', 'catch'))->setDefaultValue('true')
.
With this we'll be able to see in our console:
Request $request, $type = self::MASTER_REQUEST, $catch = true
Note: The following Models can be in a collection:
Argument
,Constant
,Contract
(class/interface parents),FullyQualifiedName
(use statements),Method
andProperty
.
As explained above, a Method
can have a collection of Arguments
(0 to many).
In order to describe this method, we don't need to prepare an array beforehand:
use Memio\Model\Method;
$handle = Method::make('handle')
->addArgument(new Argument('Symfony\Component\HttpFoundation\Request', 'request'))
->addArgument(Argument::make('int', 'type')
->setDefaultValue('self::MASTER_REQUEST')
)
->addArgument(Argument::make('bool', 'catch')
->setDefaultValue('true')
)
;
echo $prettyPrinter->generateCode($handle);
Here's the result:
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
{
}
When running the test suite, phpspec generates missing methods in your code (amongst many other nice things). To put into practice what we've seen so far, we're going to recreate this feature using Memio:
// Those are the parameters phpspec gathers from the tests
$methodName = '__construct';
$arguments = array(new ArrayObject(), 'Nobody expects the spanish inquisition!');
// Using them we can describe the method to generate
$method = new Method($methodName);
$index = 1;
foreach ($arguments as $argument) {
$type = is_object($argument) ? get_class($argument) : gettype($argument);
$argumentName = 'argument'.$index++;
$method->addArgument(new Argument($type, $argumentName));
}
// Let's display the generated code in the console
echo $prettyPrinter->generateCode($method);
This would output:
public function __construct(ArrayObject $argument1, $argument2)
{
}
The PSR-2 Coding Standard advises us to avoid lines longer than 120 characters. Memio takes care of this when generating a method's arguments by checking the length: if it's going to be too long it'll put each arguments on their own line.
Here's a code sample:
$specification = new Method('it_is_a_very_long_method');
for ($i = 1; $i <= 7; $i++) {
$specification->addArgument(new Argument('mixed', 'argument'.$i));
}
echo $prettyPrinter->generateCode($specification);
This will output:
public function it_is_a_very_long_method(
$argument1,
$argument2,
$argument3,
$argument4,
$argument5,
$argument6,
$argument7
)
{
}
Memio assumes a few things by default:
- properties are private, not static, not abstract
- methods are public, not static, not abstract, not final
- classes are not final, not abstract
This can be customized:
$superObject = Object::make()
->makeAbstract() // can be cancelled with removeAbstract()
->makeFinal() // can be cancelled with removeFinal()
;
$publicStaticProperty = Property::make('myProperty')
->makePublic() // also available: makeProtected() and makePrivate()
->makeStatic() // can be cancelled with removeStatic()
;
$superMethod = Method::make('myMethod')
->makeAbstract() // can be cancelled with removeAbstract()
->makeFinal() // can be cancelled with removeFinal()
->makePrivate() // also available: makeProtected(), makePublic() and removeVisibility()
->makeStatic() // can be cancelled with removeStatic()
;
A constant or a default value can be many things: a string encapsulated between single or double quotes,
an integer, null... Since PHP 5.6 it can even be a numeric or string literal (e.g. __DIR__.'/path'
).
To allow all of those in the simplest possible way, Memio let us write the raw value that will be printed:
use Memio\Model\Constant;
$firstConstant = new Constant('FIRST_CONSTANT', '"string in double quotes"');
$secondConstant = new Constant('SECOND_CONSTANT', 'null');
echo $prettyPrinter->generateCode($firstConstant);
echo $prettyPrinter->generateCode($secondConstant);
This will output:
const FIRST_CONSTANT = "string in double quotes";
const SECOND_CONSTANT = null;
In PHP, class
and interface
are two reserved keywords. In order to be able to
have Models describing those, Memio provides respectively Object
and Contract
.
Here's an example of interface generation:
use Memio\Model\Contract;
$myMethod = new Method('myMethod')
->addArgument('mixed', 'myArgument')
);
$myContract = Contract::make('Vendor\Project\MyInterface')
->extend(new Contract('Vendor\Project\MyParentInterface'))
->addConstant(new Constant('MY_CONSTANT', '42'))
->addMethod($myMethod)
;
echo $prettyPrinter->generateCode($myContract);
Will output:
interface MyInterface extends MyParentInterface
{
const MY_CONSTANT = 42;
public function myMethod($myArgument);
}
Objects can extend only one parent, but can implement many interfaces. Contracts can extend many interfaces.
Finally, we can generate a whole File
:
$myFile = File::make('src/Vendor/Project/MyObject')
->addFullyQualifiedName($myContract->getFullyQualifiedName())
->setStructure(Object::make('Vendor\Project\MyObject')
->implement($myContract)
->addMethod($myMethod)
)
;
$prettyPrinter->generateCode($myFile);
This will output:
<?php
namespace Vendor\Project;
use Vendor\Project\MyInterface;
class MyObject implements MyInterface
{
public function myMethod($myArgument)
{
}
}
Previous pages: