Skip to content
This repository was archived by the owner on Dec 29, 2020. It is now read-only.

Commit 65cb453

Browse files
authored
Merge pull request #25 from ricordisamoa/nullable-types
Support PHP 7.1 nullable types (#16)
2 parents f0b674f + 9a0c6c1 commit 65cb453

File tree

6 files changed

+188
-10
lines changed

6 files changed

+188
-10
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Supports:
5959
* methods of classes and traits
6060
* method definitions in interfaces
6161
* PHPDoc inheritance
62+
* PHP 7.1 nullable types (can be disabled with `--no-nullable-types` option)
6263

6364
## Credits
6465

src/ConvertCommand.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ protected function configure()
5555
->setDescription('Convert files')
5656
->addOption('exclude', 'e', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Directories to exclude', ['vendor'])
5757
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Displays diff instead of modifying files')
58+
->addOption('no-nullable-types', null, InputOption::VALUE_NONE, 'Uses a default `null` value instead of PHP 7.1 nullable types')
5859
->addArgument('input', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Input directories', ['.'])
5960
;
6061
}
@@ -87,7 +88,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
8788
$changed = [];
8889
foreach ($project->getFiles() as $file) {
8990
$old = $file->getSource();
90-
$new = $converter->convert($project, $file);
91+
$new = $converter->convert($project, $file, !$input->getOption('no-nullable-types'));
9192

9293
if ($new !== $old) {
9394
if ($input->getOption('dry-run')) {

src/Converter.php

+16-5
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@ class Converter
5555
*
5656
* @param Project $project
5757
* @param File $file
58+
* @param bool $nullableTypes
5859
*
5960
* @return string
6061
*/
61-
public function convert(Project $project, File $file): string
62+
public function convert(Project $project, File $file, bool $nullableTypes): string
6263
{
6364
$tokens = token_get_all($file->getSource());
6465

@@ -129,12 +130,12 @@ public function convert(Project $project, File $file): string
129130
if (null !== $function && $outputReturn) {
130131
$return = $this->getReturn($project, $objectType, $namespace, $object, $function);
131132

132-
if ($return && $return[0] && !$return[1]) {
133+
if ($return && $return[0] && (!$return[1] || $nullableTypes)) {
133134
if ($endsInNewLine = $this->endsInNewLine($output)) {
134135
$output = substr($output, 0, -strlen($endsInNewLine));
135136
}
136137

137-
$output .= sprintf(': %s', $return[0]);
138+
$output .= sprintf(': %s%s', $return[1] ? '?' : '', $return[0]);
138139

139140
if ($endsInNewLine) {
140141
$output .= $endsInNewLine;
@@ -242,9 +243,13 @@ public function convert(Project $project, File $file): string
242243
$parameter = $this->getParameter($project, $objectType, $namespace, $object, $function, $text);
243244

244245
if ($parameter) {
245-
$output .= $parameter[0].' ';
246-
247246
$outputDefaultValue = (bool) $parameter[1];
247+
if ($outputDefaultValue && $nullableTypes) {
248+
$output .= '?';
249+
$outputDefaultValue = false;
250+
}
251+
252+
$output .= $parameter[0].' ';
248253
}
249254

250255
if ($paramByReference) {
@@ -550,10 +555,16 @@ private function getTypeFromTag(Tag $tag): array
550555
}
551556

552557
if (!$type0 instanceof Null_ && $type1 instanceof Null_) {
558+
if ($type0 instanceof Array_) {
559+
return ['array', true];
560+
}
553561
return [$type0->__toString(), true];
554562
}
555563

556564
if (!$type1 instanceof Null_ && $type0 instanceof Null_) {
565+
if ($type1 instanceof Array_) {
566+
return ['array', true];
567+
}
557568
return [$type1->__toString(), true];
558569
}
559570

tests/ConverterTest.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public static function setUpBeforeClass()
3535
/**
3636
* @dataProvider filesProvider
3737
*/
38-
public function testSingleFiles(string $projectName, string $fileName)
38+
public function testSingleFiles(string $projectName, string $fileName, bool $nullableTypes = null)
3939
{
4040
$projectFactory = ProjectFactory::createInstance();
4141
$project = $projectFactory->create(
@@ -46,7 +46,7 @@ public function testSingleFiles(string $projectName, string $fileName)
4646
foreach ($project->getFiles() as $file) {
4747
$this->assertStringEqualsFile(
4848
__DIR__.'/Results/'.$fileName,
49-
self::$converter->convert($project, $file)
49+
self::$converter->convert($project, $file, $nullableTypes !== null ? $nullableTypes : false)
5050
);
5151
}
5252
}
@@ -68,14 +68,14 @@ public function testInheritance()
6868
if ($childPath === $path) {
6969
$this->assertStringEqualsFile(
7070
__DIR__.'/Results/Child.php',
71-
self::$converter->convert($project, $file)
71+
self::$converter->convert($project, $file, false)
7272
);
7373
}
7474
}
7575
}
7676

7777
/**
78-
* @return string[][]
78+
* @return array[]
7979
*/
8080
public function filesProvider(): array
8181
{
@@ -90,6 +90,7 @@ public function filesProvider(): array
9090
['arrayNoTypes', 'array_no_types.php'],
9191
['typeAliasesWhitelisting', 'type_aliases_and_whitelisting.php'],
9292
['passByReference', 'pass_by_reference.php'],
93+
['nullableTypes', 'nullable_types.php', true],
9394
];
9495
}
9596
}

tests/Fixtures/nullable_types.php

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
/**
4+
* Must be converted.
5+
*
6+
* @return string|null
7+
*/
8+
function foo()
9+
{
10+
}
11+
12+
/**
13+
* Must be converted.
14+
*
15+
* @param \DateTime|null $a
16+
* @param int|null $c
17+
* @param string[]|null $d
18+
*
19+
* @return float
20+
*/
21+
function bar($a, array $b, $c, $d, bool $e, callable $f = null)
22+
{
23+
return 0.0;
24+
}
25+
26+
/**
27+
* Must not be modified (no params defined).
28+
*/
29+
function baz($a)
30+
{
31+
}
32+
33+
/**
34+
* Must be converted.
35+
*
36+
* @return bool[]|null
37+
*/
38+
function bazbaz()
39+
{
40+
}
41+
42+
/**
43+
* Must not be converted (already using type hints).
44+
*
45+
* @param int $a
46+
*
47+
* @return string
48+
*/
49+
function bat(int $a): string
50+
{
51+
}
52+
53+
/**
54+
* Must not be modified (incompatible types).
55+
*
56+
* @param int|string|null
57+
*
58+
* @return bool|int|null
59+
*/
60+
function foobar($a)
61+
{
62+
}
63+
64+
/**
65+
* Must not be converted (type hints take precedence over PHPDoc annotations).
66+
*
67+
* @param int|null $a
68+
*
69+
* @return string
70+
*/
71+
function foobaz(int $a): string
72+
{
73+
}
74+
75+
/**
76+
* Must not be converted (already using default value).
77+
*
78+
* @param int|null $a
79+
*/
80+
function foobat(int $a = null)
81+
{
82+
}

tests/Results/nullable_types.php

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
/**
4+
* Must be converted.
5+
*
6+
* @return string|null
7+
*/
8+
function foo(): ?string
9+
{
10+
}
11+
12+
/**
13+
* Must be converted.
14+
*
15+
* @param \DateTime|null $a
16+
* @param int|null $c
17+
* @param string[]|null $d
18+
*
19+
* @return float
20+
*/
21+
function bar(?\DateTime $a, array $b, ?int $c, ?array $d, bool $e, callable $f = null): float
22+
{
23+
return 0.0;
24+
}
25+
26+
/**
27+
* Must not be modified (no params defined).
28+
*/
29+
function baz($a)
30+
{
31+
}
32+
33+
/**
34+
* Must be converted.
35+
*
36+
* @return bool[]|null
37+
*/
38+
function bazbaz(): ?array
39+
{
40+
}
41+
42+
/**
43+
* Must not be converted (already using type hints).
44+
*
45+
* @param int $a
46+
*
47+
* @return string
48+
*/
49+
function bat(int $a): string
50+
{
51+
}
52+
53+
/**
54+
* Must not be modified (incompatible types).
55+
*
56+
* @param int|string|null
57+
*
58+
* @return bool|int|null
59+
*/
60+
function foobar($a)
61+
{
62+
}
63+
64+
/**
65+
* Must not be converted (type hints take precedence over PHPDoc annotations).
66+
*
67+
* @param int|null $a
68+
*
69+
* @return string
70+
*/
71+
function foobaz(int $a): string
72+
{
73+
}
74+
75+
/**
76+
* Must not be converted (already using default value).
77+
*
78+
* @param int|null $a
79+
*/
80+
function foobat(int $a = null)
81+
{
82+
}

0 commit comments

Comments
 (0)