Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/vendor/
.php_cs.cache
composer.lock
.devcontainer
.php-cs-fixer.cache
.phpunit.result.cache
80 changes: 80 additions & 0 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

$finder = PhpCsFixer\Finder::create()->in(__DIR__);

return (new PhpCsFixer\Config())
->setRules([
'@PSR12' => true,
'array_syntax' => [
'syntax' => 'short',
],
'binary_operator_spaces' => [
'operators' => [
'=>' => 'align',
'=' => 'align',
],
],
'concat_space' => [
'spacing' => 'one',
],
'declare_strict_types' => true,
'type_declaration_spaces' => true,
'single_line_comment_style' => [
'comment_types' => ['hash'],
],
'lowercase_cast' => true,
'class_attributes_separation' => [
'elements' => ['method' => 'one', 'property' => 'one', 'const' => 'one'],
],
'native_function_casing' => true,
'new_with_parentheses' => true,
'no_alias_functions' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'multiline_whitespace_before_semicolons' => false,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_around_offset' => true,
'no_trailing_comma_in_singleline' => true,
'no_unreachable_default_argument_value' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'object_operator_without_whitespace' => true,
'ordered_imports' => true,
'phpdoc_align' => true,
'phpdoc_indent' => true,
'general_phpdoc_tag_rename' => true,
'phpdoc_inline_tag_normalizer' => true,
'phpdoc_tag_type' => true,
'phpdoc_order' => true,
'phpdoc_scalar' => true,
'phpdoc_separation' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
'self_accessor' => true,
'short_scalar_cast' => true,
'single_quote' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'trailing_comma_in_multiline' => [
'elements' => ['arrays'],
],
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
])
->setRiskyAllowed(true)
->setUsingCache(true)
->setFinder($finder);
19 changes: 0 additions & 19 deletions .php_cs

This file was deleted.

11 changes: 5 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
language: php

php:
- 5.6
- 7.0
- hhvm
- 8.1
- 8.2
- 8.3
- 8.4

cache:
directories:
Expand All @@ -20,6 +21,4 @@ script:
- composer test

matrix:
fast_finish: true
allow_failures:
- php: hhvm
fast_finish: true
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [2.0.0] - 2025-08-13
### Changed
* Minimum supported PHP version is now `8.1`.

## [1.0.0] - 2016-09-09
### Changed
* Moved `TomPHP\ExceptionConstructorTools\ExceptionConstructorTools` to
Expand Down
20 changes: 16 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
}
],
"require": {
"php": "^5.6|^7.0"
"php": ">=8.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^1.10",
"phpunit/phpunit": "^5.5",
"squizlabs/php_codesniffer": "*"
"friendsofphp/php-cs-fixer": "^3.85",
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^9.6 || ^7.5 || ^11.5",
"rector/rector": "^2.1",
"squizlabs/php_codesniffer": "^3.9"
},
"autoload": {
"psr-4": {
Expand All @@ -44,8 +46,18 @@
"phpcs --standard=psr2 src tests",
"php-cs-fixer fix --dry-run --verbose"
],
"analyse": [
"phpstan analyse --memory-limit=1G"
],
"rector": [
"rector process src tests --ansi"
],
"rector:dry": [
"rector process src tests --dry-run --ansi"
],
"test": [
"@cs:check",
"@analyse",
"phpunit --colors=always"
]
}
Expand Down
8 changes: 8 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
parameters:
level: max

paths:
- src/
- tests/

treatPhpDocTypesAsCertain: false
34 changes: 34 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;

return RectorConfig::configure()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/tests',
])
// Ensure Rector knows we are targeting PHP 8.1+ syntax and features
->withPhpSets(php81: true)
->withPreparedSets(
typeDeclarations: true, // Add param/return/var types where possible
earlyReturn: true, // Replace nested ifs with early returns
strictBooleans: true, // Use strict bool checks
phpunitCodeQuality: true, // Modernise PHPUnit usage
deadCode: true // Remove unused code, vars, imports, etc.
)
->withSets([
LevelSetList::UP_TO_PHP_81, // Enforces all rules up to PHP 8.1
SetList::CODE_QUALITY,
SetList::CODING_STYLE,
SetList::DEAD_CODE,
SetList::NAMING, // Enforce clear & consistent naming
SetList::TYPE_DECLARATION, // Add missing type declarations aggressively
SetList::PRIVATIZATION, // Make props/methods private if possible
SetList::STRICT_BOOLEANS, // Strict boolean expressions
])->withPHPStanConfigs([
__DIR__ . '/phpstan.neon.dist',
]);
67 changes: 32 additions & 35 deletions src/ExceptionConstructorTools.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace TomPHP;

/**
Expand All @@ -11,69 +13,64 @@ trait ExceptionConstructorTools
/**
* Create an instance of the exception with a formatted message.
*
* @param string $message The exception message in sprintf format.
* @param array $params The sprintf parameters for the message.
* @param int $code Numeric exception code.
* @param \Exception $previous The previous exception.
*
* @return static
* @param string $message The exception message in sprintf format.
* @param array<bool|float|int|string|null> $params The sprintf parameters for the message.
* @param int $code Numeric exception code.
* @param \Exception $exception The previous exception.
*/
protected static function create(
$message,
string $message,
array $params = [],
$code = 0,
\Exception $previous = null
) {
return new static(sprintf($message, ...$params), $code, $previous);
int $code = 0,
?\Exception $exception = null
): static {
$class = static::class;
$reflectionClass = new \ReflectionClass($class);
return $reflectionClass->newInstance(sprintf($message, ...$params), $code, $exception);
}

/**
* Returns a string representation of the type of a variable.
*
* @param mixed $variable
*
* @return string
*/
protected static function typeToString($variable)
protected static function typeToString(mixed $variable): string
{
return is_object($variable)
? get_class($variable)
? $variable::class
: '[' . gettype($variable) . ']';
}

/**
* Returns a string representation of the value.
*
* @param mixed $value
*
* @return string
*/
protected static function valueToString($value)
protected static function valueToString(mixed $value): string
{
switch (gettype($value)) {
case 'string':
return '"' . addslashes($value) . '"';
case 'boolean':
return $value ? 'true' : 'false';
default:
return $value;
if (!is_string($value)
&& !is_numeric($value)
&& !is_bool($value)
&& !$value instanceof \Stringable
) {
throw new \InvalidArgumentException("Value isn't stringable");
}

return match (gettype($value)) {
'string' => '"' . addslashes($value) . '"',
'boolean' => $value ? 'true' : 'false',
default => (string) $value,
};
}

/**
* Returns the list as a formatted string.
*
* @param string[] $list
*
* @return string
* @param array<mixed> $list
*/
protected static function listToString(array $list)
protected static function listToString(array $list): string
{
if (empty($list)) {
if ($list === []) {
return '[]';
}

$list = array_map(['static', 'valueToString'], $list);
$list = array_map(fn ($item): string => static::valueToString($item), $list);

return '[' . implode(', ', $list) . ']';
}
Expand Down
28 changes: 20 additions & 8 deletions tests/support/ExampleException.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace tests\support;

use TomPHP\ExceptionConstructorTools;
Expand All @@ -8,32 +10,42 @@ class ExampleException extends \RuntimeException
{
use ExceptionConstructorTools;

public static function fromFormatString($format, $param)
/**
* @param array<bool|float|int|string|null>|bool|float|int|string|null $param
*/
public static function fromFormatString(string $format, array|bool|float|int|string|null $param): static
{
return self::create($format, [$param]);
if (!is_array($param)) {
$param = [$param];
}

return self::create($format, $param);
}

public static function fromCode($code)
public static function fromCode(int $code): static
{
return self::create('', [], $code);
}

public static function fromPreviousException($previous)
public static function fromPreviousException(?\Exception $exception): static
{
return self::create('', [], 0, $previous);
return self::create('', [], 0, $exception);
}

public static function withTypeInMessage($param)
public static function withTypeInMessage(mixed $param): static
{
return self::create(self::typeToString($param));
}

public static function withValueInMessage($value)
public static function withValueInMessage(mixed $value): static
{
return self::create(self::valueToString($value));
}

public static function withListInMessage($param)
/**
* @param array<mixed> $param
*/
public static function withListInMessage(array $param): static
{
return self::create(self::listToString($param));
}
Expand Down
2 changes: 2 additions & 0 deletions tests/support/ExampleExtendedException.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace tests\support;

final class ExampleExtendedException extends ExampleException
Expand Down
Loading