Typehint and phpdoc improvements based on phpstan

Fix low hanging fruit from running phpstan with level 2 checking.
Also adds a basic psalm config and a new composer run-script target
('analyse') to execute both tools.

Tool dependencies are intentially not added to avoid unnecessary bloat
and download time in travis.

This is intended as a purely manual tool for regression checking and a
help to iteratively improve the codebase.
This commit is contained in:
DerManoMann 2020-09-02 11:59:52 +12:00
parent 3a49674483
commit 78a2ef24aa
13 changed files with 44 additions and 37 deletions

View File

@ -66,6 +66,10 @@
"phpunit",
"@lint"
],
"analyse": [
"phpstan analyze --level=2 src | grep -v 'does not accept default value of type string'",
"psalm"
],
"docs": "./docs/node_modules/.bin/vuepress dev docs/",
"deploy_docs": "./docs/node_modules/.bin/vuepress build docs/ && cp -r .git docs/.vuepress/dist/.git && cd docs/.vuepress/dist/ && git symbolic-ref HEAD refs/heads/gh-pages && git add --all"
}

15
psalm.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
errorLevel="7"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>

View File

@ -56,7 +56,7 @@ class Analyser
/**
* Allows Annotation classes to know the context of the annotation that is being processed.
*
* @var Context
* @var null|Context
*/
public static $context;

View File

@ -70,7 +70,7 @@ class Analysis
/**
* Registry for the post-processing operations.
*
* @var Closure[]
* @var callable[]
*/
private static $processors;
@ -89,11 +89,7 @@ class Analysis
}
}
/**
* @param AbstractAnnotation $annotation
* @param Context $context
*/
public function addAnnotation($annotation, $context)
public function addAnnotation($annotation, ?Context $context)
{
if ($this->annotations->contains($annotation)) {
return;
@ -182,9 +178,8 @@ class Analysis
$this->classes = array_merge($this->classes, $analysis->classes);
$this->interfaces = array_merge($this->interfaces, $analysis->interfaces);
$this->traits = array_merge($this->traits, $analysis->traits);
if ($this->openapi === null && $analysis->openapi) {
if ($this->openapi === null && $analysis->openapi !== null) {
$this->openapi = $analysis->openapi;
$analysis->target->_context->analysis = $this;
}
}
@ -407,7 +402,7 @@ class Analysis
*/
public function merged()
{
if (!$this->openapi) {
if ($this->openapi === null) {
throw new Exception('No openapi target set. Run the MergeIntoOpenApi processor');
}
$unmerged = $this->openapi->_unmerged;
@ -524,7 +519,7 @@ class Analysis
public function validate()
{
if ($this->openapi) {
if ($this->openapi !== null) {
return $this->openapi->validate();
}
Logger::notice('No openapi target set. Run the MergeIntoOpenApi processor before validate()');

View File

@ -471,7 +471,7 @@ abstract class AbstractAnnotation implements JsonSerializable
*
* @param array|object $fields
* @param array $parents the path of annotations above this annotation in the tree
* @param array [ $skip] Array with objects which are already validated
* @param array $skip List of objects already validated
*
* @return bool
*/

View File

@ -81,7 +81,7 @@ class Components extends AbstractAnnotation
/**
* Reusable Callbacks.
*
* @var callback[]
* @var callable[]
*/
public $callbacks = UNDEFINED;

View File

@ -83,7 +83,7 @@ class Flow extends AbstractAnnotation
public function jsonSerialize()
{
if (is_array($this->scopes) && empty($this->scopes)) {
$this->scopes = new \StdClass();
$this->scopes = new \stdClass();
}
return parent::jsonSerialize();

View File

@ -178,9 +178,6 @@ class OpenApi extends AbstractAnnotation
/**
* Recursive helper for ref().
*
* @param * $container the container to resolve the ref in
* @param array $mapping
*/
private static function resolveRef($ref, $resolved, $container, $mapping)
{

View File

@ -104,7 +104,7 @@ abstract class Operation extends AbstractAnnotation
* Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses.
* The key value used to identify the callback object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation.
*
* @var callback[]
* @var callable[]
*/
public $callbacks = UNDEFINED;

View File

@ -121,10 +121,12 @@ class SecurityScheme extends AbstractAnnotation
*/
public function merge($annotations, $ignore = false)
{
parent::merge($annotations, $ignore);
$unmerged = parent::merge($annotations, $ignore);
if ($this->type === 'oauth2') {
$this->name = UNDEFINED;
}
return $unmerged;
}
}

View File

@ -34,6 +34,9 @@ namespace OpenApi;
* @property string $type
* @property string $trait
* @property string $interface
* @property bool $static Indicate a static method
* @property bool $generated Indicate the context was generated by a processor
* @property Annotations\AbstractAnnotation $nested
* @property Annotations\AbstractAnnotation[] $annotations
*/
class Context
@ -93,7 +96,7 @@ class Context
if (property_exists($this, $property)) {
return $this;
}
if ($this->_parent) {
if ($this->_parent !== null) {
return $this->_parent->with($property);
}
@ -105,7 +108,7 @@ class Context
*/
public function getRootContext()
{
if ($this->_parent) {
if ($this->_parent !== null) {
return $this->_parent->getRootContext();
}
@ -154,7 +157,7 @@ class Context
*/
public function __get($property)
{
if ($this->_parent) {
if ($this->_parent !== null) {
return $this->_parent->$property;
}
@ -292,10 +295,8 @@ class Context
* Resolve the fully qualified name.
*
* @param string $source The source name (class/interface/trait)
*
* @return string
*/
public function fullyQualifiedName($source)
public function fullyQualifiedName(?string $source): string
{
if ($source === null) {
return '';

View File

@ -6,7 +6,6 @@
namespace OpenApi;
use Closure;
use Exception;
/**
@ -22,7 +21,7 @@ class Logger
public static $instance;
/**
* @var Closure
* @var callable
*/
public $log;
@ -75,9 +74,9 @@ class Logger
/**
* Shorten class name(s).
*
* @param string|object|[] $classes Class(es) to shorten
* @param array|object|string $classes Class(es) to shorten
*
* @return string|[] One or more shortened class names
* @return string|string[] One or more shortened class names
*/
public static function shorten($classes)
{

View File

@ -73,14 +73,11 @@ class Serializer
/**
* Deserialize a string.
*
* @param $jsonString
* @param $className
*
* @throws \Exception
*
* @return OA\AbstractAnnotation
*/
public function deserialize($jsonString, $className)
public function deserialize(string $jsonString, string $className)
{
if (!$this->isValidAnnotationClass($className)) {
throw new \Exception($className.' is not defined in OpenApi PHP Annotations');
@ -92,14 +89,11 @@ class Serializer
/**
* Deserialize a file.
*
* @param $filename
* @param $className
*
* @throws \Exception
*
* @return OA\AbstractAnnotation
*/
public function deserializeFile($filename, $className = 'OpenApi\Annotations\OpenApi')
public function deserializeFile(string $filename, string $className = 'OpenApi\Annotations\OpenApi')
{
if (!$this->isValidAnnotationClass($className)) {
throw new \Exception($className.' is not defined in OpenApi PHP Annotations');