Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] PHPStan at max level #227

Draft
wants to merge 1 commit into
base: 3.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/.github/ export-ignore
/.gitignore export-ignore
/examples export-ignore
/phpstan.neon.dist export-ignore
/phpunit.xml.dist export-ignore
/phpunit.xml.legacy export-ignore
/tests export-ignore
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,26 @@ jobs:
ini-file: development
- run: composer install
- run: vendor/bin/phpunit --coverage-text

PHPStan:
name: PHPStan (PHP ${{ matrix.php }})
runs-on: ubuntu-22.04
strategy:
matrix:
php:
- 8.3
- 8.2
- 8.1
- 8.0
- 7.4
- 7.3
- 7.2
- 7.1
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
- run: composer install
- run: vendor/bin/phpstan
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"react/promise": "^3.2 || ^2.7 || ^1.2.1"
},
"require-dev": {
"phpstan/phpstan": "1.11.1 || 1.4.10",
"phpunit/phpunit": "^9.6 || ^7.5",
"react/async": "^4.3 || ^3 || ^2",
"react/promise-timer": "^1.11"
Expand Down
4 changes: 3 additions & 1 deletion examples/01-one.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@

$resolver->resolve($name)->then(function ($ip) use ($name) {
echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});
4 changes: 3 additions & 1 deletion examples/02-concurrent.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@
foreach ($names as $name) {
$resolver->resolve($name)->then(function ($ip) use ($name) {
echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});
}
16 changes: 12 additions & 4 deletions examples/03-cached.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,30 @@

$resolver->resolve($name)->then(function ($ip) use ($name) {
echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});

Loop::addTimer(1.0, function() use ($name, $resolver) {
$resolver->resolve($name)->then(function ($ip) use ($name) {
echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});
});

Loop::addTimer(2.0, function() use ($name, $resolver) {
$resolver->resolve($name)->then(function ($ip) use ($name) {
echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});
});

Loop::addTimer(3.0, function() use ($name, $resolver) {
$resolver->resolve($name)->then(function ($ip) use ($name) {
echo 'IP for ' . $name . ': ' . $ip . PHP_EOL;
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});
});
9 changes: 5 additions & 4 deletions examples/11-all-ips.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
$resolver = $factory->create($config);

$name = $argv[1] ?? 'www.google.com';
assert(is_string($name));

$resolver->resolveAll($name, Message::TYPE_A)->then(function (array $ips) use ($name) {
$resolver->resolveAll($name, Message::TYPE_A)->then(static function (array $ips) use ($name): void {
echo 'IPv4 addresses for ' . $name . ': ' . implode(', ', $ips) . PHP_EOL;
}, function (Exception $e) use ($name) {
}, function (Throwable $e) use ($name) {
echo 'No IPv4 addresses for ' . $name . ': ' . $e->getMessage() . PHP_EOL;
});

$resolver->resolveAll($name, Message::TYPE_AAAA)->then(function (array $ips) use ($name) {
$resolver->resolveAll($name, Message::TYPE_AAAA)->then(static function (array $ips) use ($name): void {
echo 'IPv6 addresses for ' . $name . ': ' . implode(', ', $ips) . PHP_EOL;
}, function (Exception $e) use ($name) {
}, function (Throwable $e) use ($name) {
echo 'No IPv6 addresses for ' . $name . ': ' . $e->getMessage() . PHP_EOL;
});
9 changes: 6 additions & 3 deletions examples/12-all-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
$resolver = $factory->create($config);

$name = $argv[1] ?? 'google.com';
$type = constant('React\Dns\Model\Message::TYPE_' . ($argv[2] ?? 'TXT'));
assert(is_string($name));

$resolver->resolveAll($name, $type)->then(function (array $values) {
$type = constant('React\Dns\Model\Message::TYPE_' . ($type ?? 'TXT'));
assert(is_int($type));

$resolver->resolveAll($name, $type)->then(static function (array $values): void {
var_dump($values);
}, function (Exception $e) {
}, function (Throwable $e) {
echo $e->getMessage() . PHP_EOL;
});
13 changes: 8 additions & 5 deletions examples/13-reverse-dns.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,22 @@
$resolver = $factory->create($config);

$ip = $argv[1] ?? '8.8.8.8';
assert(is_string($ip));
$ip = @inet_pton($ip);

if (@inet_pton($ip) === false) {
if ($ip === false) {
exit('Error: Given argument is not a valid IP' . PHP_EOL);
}

if (strpos($ip, ':') === false) {
$name = inet_ntop(strrev(inet_pton($ip))) . '.in-addr.arpa';
$name = inet_ntop(strrev($ip)) . '.in-addr.arpa';
} else {
$name = wordwrap(strrev(bin2hex(inet_pton($ip))), 1, '.', true) . '.ip6.arpa';
$name = wordwrap(strrev(bin2hex($ip)), 1, '.', true) . '.ip6.arpa';
}
assert(is_string($name));

$resolver->resolveAll($name, Message::TYPE_PTR)->then(function (array $names) {
var_dump($names);
}, function (Exception $e) {
echo $e->getMessage() . PHP_EOL;
}, static function (Throwable $error) {
echo $error;
});
15 changes: 11 additions & 4 deletions examples/91-query-a-and-aaaa.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,24 @@
$executor = new UdpTransportExecutor('8.8.8.8:53');

$name = $argv[1] ?? 'www.google.com';
assert(is_string($name));

$ipv4Query = new Query($name, Message::TYPE_A, Message::CLASS_IN);
$ipv6Query = new Query($name, Message::TYPE_AAAA, Message::CLASS_IN);

$executor->query($ipv4Query)->then(function (Message $message) {
$executor->query($ipv4Query)->then(static function (Message $message): void {
foreach ($message->answers as $answer) {
assert(\is_string($answer->data));
echo 'IPv4: ' . $answer->data . PHP_EOL;
}
}, 'printf');
$executor->query($ipv6Query)->then(function (Message $message) {
}, static function (Throwable $error) {
echo $error;
});
$executor->query($ipv6Query)->then(static function (Message $message): void {
foreach ($message->answers as $answer) {
assert(\is_string($answer->data));
echo 'IPv6: ' . $answer->data . PHP_EOL;
}
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});
21 changes: 17 additions & 4 deletions examples/92-query-any.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,68 +14,81 @@
$executor = new TcpTransportExecutor('8.8.8.8:53');

$name = $argv[1] ?? 'google.com';
assert(is_string($name));

$any = new Query($name, Message::TYPE_ANY, Message::CLASS_IN);

$executor->query($any)->then(function (Message $message) {
$executor->query($any)->then(function (Message $message): void {
foreach ($message->answers as $answer) {
/* @var $answer Record */

$data = $answer->data;

switch ($answer->type) {
case Message::TYPE_A:
assert(\is_string($data));
$type = 'A';
break;
case Message::TYPE_AAAA:
assert(\is_string($data));
$type = 'AAAA';
break;
case Message::TYPE_NS:
assert(\is_string($data));
$type = 'NS';
break;
case Message::TYPE_PTR:
assert(\is_string($data));
$type = 'PTR';
break;
case Message::TYPE_CNAME:
assert(\is_string($data));
$type = 'CNAME';
break;
case Message::TYPE_TXT:
assert(\is_array($data));
// TXT records can contain a list of (binary) strings for each record.
// here, we assume this is printable ASCII and simply concatenate output
$type = 'TXT';
$data = implode('', $data);
break;
case Message::TYPE_MX:
assert(\is_array($data));
// MX records contain "priority" and "target", only dump its values here
$type = 'MX';
$data = implode(' ', $data);
break;
case Message::TYPE_SRV:
assert(\is_array($data));
// SRV records contain priority, weight, port and target, dump structure here
$type = 'SRV';
$data = json_encode($data);
break;
case Message::TYPE_SSHFP:
assert(\is_array($data));
// SSHFP records contain algorithm, fingerprint type and hex fingerprint value
$type = 'SSHFP';
$data = implode(' ', $data);
break;
case Message::TYPE_SOA:
assert(\is_array($data));
// SOA records contain structured data, dump structure here
$type = 'SOA';
$data = json_encode($data);
break;
case Message::TYPE_CAA:
assert(\is_array($data));
// CAA records contains flag, tag and value
$type = 'CAA';
$data = $data['flag'] . ' ' . $data['tag'] . ' "' . $data['value'] . '"';
break;
default:
assert(\is_string($data));
// unknown type uses HEX format
$type = 'TYPE' . $answer->type;
$data = wordwrap(strtoupper(bin2hex($data)), 2, ' ', true);
}

echo $type . ': ' . $data . PHP_EOL;
}
}, 'printf');
}, static function (Throwable $error) {
echo $error;
});
7 changes: 7 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
parameters:
level: max

paths:
- examples/
- src/
- tests/
11 changes: 7 additions & 4 deletions src/Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class Config
* @return self
* @codeCoverageIgnore
*/
public static function loadSystemConfigBlocking()
public static function loadSystemConfigBlocking(): self
{
// Use WMIC output on Windows
if (DIRECTORY_SEPARATOR === '\\') {
Expand Down Expand Up @@ -71,7 +71,7 @@ public static function loadSystemConfigBlocking()
* @return self
* @throws RuntimeException if the path can not be loaded (does not exist)
*/
public static function loadResolvConfBlocking($path = null)
public static function loadResolvConfBlocking(?string $path = null): self
{
if ($path === null) {
$path = '/etc/resolv.conf';
Expand Down Expand Up @@ -122,16 +122,19 @@ public static function loadResolvConfBlocking($path = null)
* @return self
* @link https://ss64.com/nt/wmic.html
*/
public static function loadWmicBlocking($command = null)
public static function loadWmicBlocking(?string $command = null): self
{
$contents = shell_exec($command === null ? 'wmic NICCONFIG get "DNSServerSearchOrder" /format:CSV' : $command);
preg_match_all('/(?<=[{;,"])([\da-f.:]{4,})(?=[};,"])/i', $contents, $matches);
preg_match_all('/(?<=[{;,"])([\da-f.:]{4,})(?=[};,"])/i', $contents, $matches); /** @phpstan-ignore-line */

$config = new self();
$config->nameservers = $matches[1];

return $config;
}

/**
* @var array<string>
*/
public $nameservers = [];
}
Loading
Loading