diff --git a/composer.json b/composer.json
index 8d51c63..0444c71 100644
--- a/composer.json
+++ b/composer.json
@@ -54,5 +54,8 @@
"js/tests"
]
}
+ },
+ "scripts": {
+ "psalm": "psalm --config=config/psalm.xml"
}
}
diff --git a/config/psalm.xml b/config/psalm.xml
new file mode 100644
index 0000000..5991740
--- /dev/null
+++ b/config/psalm.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Event/Hybrid_Events.php b/src/Event/Hybrid_Events.php
index 1df52d6..60f051c 100644
--- a/src/Event/Hybrid_Events.php
+++ b/src/Event/Hybrid_Events.php
@@ -21,6 +21,7 @@ class Hybrid_Events implements Hook_Event_Config_Interface {
return $events;
}
+ /** @var string $prefix */
$prefix = hybrid_get_prefix();
$events["{$prefix}_before_header"][10] = [
@@ -34,9 +35,11 @@ class Hybrid_Events implements Hook_Event_Config_Interface {
'category' => 'theme',
];
+ /** @var array $sidebars */
$sidebars = get_theme_support( 'hybrid-core-sidebars' );
if ( ! empty( $sidebars[0] ) ) {
+ /** @var string $sidebar */
foreach ( $sidebars[0] as $sidebar ) {
$events["{$prefix}_before_{$sidebar}"][10] = [
diff --git a/src/Formatter/Backtrace_Formatter.php b/src/Formatter/Backtrace_Formatter.php
index 242c421..8dc4352 100644
--- a/src/Formatter/Backtrace_Formatter.php
+++ b/src/Formatter/Backtrace_Formatter.php
@@ -8,7 +8,7 @@ namespace Rarst\Laps\Formatter;
*/
class Backtrace_Formatter {
- /** @var array $skip String matches to omit. */
+ /** @var string[] $skip String matches to omit. */
protected static $skip = [
'wp-blog-header.php',
'wp-load.php',
@@ -74,9 +74,13 @@ class Backtrace_Formatter {
}
/**
+ *
* @param string $item Backtrace item.
*
* @return string
+ *
+ * @psalm-suppress PossiblyFalseOperand
+ * @psalm-suppress MixedInferredReturnType
*/
protected function shorten_include( string $item ): string {
diff --git a/src/Manager/Toolbar_Manager.php b/src/Manager/Toolbar_Manager.php
index 073630c..8a38e7d 100644
--- a/src/Manager/Toolbar_Manager.php
+++ b/src/Manager/Toolbar_Manager.php
@@ -29,6 +29,8 @@ class Toolbar_Manager {
* Render interface and add to the toolbar.
*
* @param \WP_Admin_Bar $wp_admin_bar WordPress core toolbar object.
+ *
+ * @psalm-suppress MixedArgument
*/
public function admin_bar_menu( \WP_Admin_Bar $wp_admin_bar ): void {
diff --git a/src/Mustache_Cache_FrozenCache.php b/src/Mustache_Cache_FrozenCache.php
index a38fef5..08427c3 100644
--- a/src/Mustache_Cache_FrozenCache.php
+++ b/src/Mustache_Cache_FrozenCache.php
@@ -15,6 +15,8 @@ class Mustache_Cache_FrozenCache extends \Mustache_Cache_FilesystemCache {
* @param string $value Value.
*
* @return void
+ *
+ * @psalm-suppress InvalidScalarArgument
*/
public function cache( $key, $value ): void {
diff --git a/src/Plugin.php b/src/Plugin.php
index 2716938..4af88ba 100644
--- a/src/Plugin.php
+++ b/src/Plugin.php
@@ -20,6 +20,9 @@ class Plugin extends Container {
/**
* @param array $values Configuration values to apply.
+ *
+ * @psalm-suppress MixedArgument
+ * @psalm-suppress MixedAssignment
*/
public function __construct( array $values = [] ) {
@@ -60,6 +63,8 @@ class Plugin extends Container {
/**
* Start Stopwatch and timing plugin load immediately, then set up core events and needed hooks.
+ *
+ * @psalm-suppress MixedAssignment
*/
public function run(): void {
diff --git a/src/Record/Core_Load_Collector.php b/src/Record/Core_Load_Collector.php
index e39c41c..d946f3b 100644
--- a/src/Record/Core_Load_Collector.php
+++ b/src/Record/Core_Load_Collector.php
@@ -27,6 +27,10 @@ class Core_Load_Collector implements Record_Collector_Interface {
$request_time = filter_var( $_SERVER['REQUEST_TIME_FLOAT'], FILTER_VALIDATE_FLOAT );
+ /**
+ * @var float $request_time
+ * @var float $timestart
+ */
return [
new Record( 'PHP Load', $request_time, $timestart - $request_time, '', 'php' ),
// TODO This includes network plugins on multisite, need conditional label if Laps is network–activated.
diff --git a/src/Record/Hook_Record_Collector.php b/src/Record/Hook_Record_Collector.php
index df99cba..2cd7373 100644
--- a/src/Record/Hook_Record_Collector.php
+++ b/src/Record/Hook_Record_Collector.php
@@ -18,8 +18,8 @@ class Hook_Record_Collector extends Stopwatch_Record_Collector {
protected $events = [];
/**
- * @param Stopwatch $stopwatch Stopwatch instance.
- * @param array $event_configs Starts and stops configuration.
+ * @param Stopwatch $stopwatch Stopwatch instance.
+ * @param Hook_Event_Config_Interface[] $event_configs Starts and stops configuration.
*/
public function __construct( Stopwatch $stopwatch, array $event_configs ) {
@@ -42,7 +42,12 @@ class Hook_Record_Collector extends Stopwatch_Record_Collector {
$this->events = array_merge( $this->events, $stops );
+ /**
+ * @var string $hook_name
+ * @var array $data
+ */
foreach ( $stops as $hook_name => $data ) {
+ /** @var int $priority */
foreach ( array_keys( $data ) as $priority ) {
add_action( $hook_name, [ $this, 'tick' ], $priority );
}
@@ -70,8 +75,14 @@ class Hook_Record_Collector extends Stopwatch_Record_Collector {
global $wp_filter;
+ /** @var string $filter_name */
$filter_name = current_filter();
+ /**
+ * @var \WP_Hook|array $filter_instance
+ * @var array $wp_filter
+ */
$filter_instance = $wp_filter[ $filter_name ];
+ /** @var int $priority */
$priority = $filter_instance instanceof \WP_Hook ? $filter_instance->current_priority() : key( $filter_instance );
// See https://core.trac.wordpress.org/ticket/41185 on broken priority, but more general sanity check.
diff --git a/src/Record/Recursive_Record_Iterator.php b/src/Record/Recursive_Record_Iterator.php
index 51ba241..c8945ce 100644
--- a/src/Record/Recursive_Record_Iterator.php
+++ b/src/Record/Recursive_Record_Iterator.php
@@ -8,7 +8,7 @@ namespace Rarst\Laps\Record;
*/
class Recursive_Record_Iterator extends \ArrayIterator implements \RecursiveIterator {
- /** @var array $children */
+ /** @var Record_Interface[] $children */
protected $children = [];
/**
diff --git a/src/Record/Sql_Record_Collector.php b/src/Record/Sql_Record_Collector.php
index 2ba0fa6..021b9d0 100644
--- a/src/Record/Sql_Record_Collector.php
+++ b/src/Record/Sql_Record_Collector.php
@@ -34,12 +34,15 @@ class Sql_Record_Collector implements Record_Collector_Interface {
* @param string $query SQL query.
*
* @return string
+ *
+ * @psalm-suppress MixedPropertyFetch
*/
public function query( $query ): string {
global $wpdb;
if ( empty( $this->query_starts ) && ! empty( $wpdb->queries ) ) {
+ /** @var array $wpdb->queries */
$this->query_starts[ count( $wpdb->queries ) ] = microtime( true );
} else {
$this->query_starts[] = microtime( true );
@@ -59,6 +62,7 @@ class Sql_Record_Collector implements Record_Collector_Interface {
global $wpdb;
+ /** @var array $wpdb->queries */
return array_map( [ $this, 'transform' ], array_keys( $wpdb->queries ), $wpdb->queries );
}
@@ -75,6 +79,7 @@ class Sql_Record_Collector implements Record_Collector_Interface {
*
* @param int $key Query key in captured data.
* @param array $query_data Array of captured query data.
+ * @psalm-param array{0: string, 1: float, 2: string} $query_data
*
* @return Record
*/
@@ -84,6 +89,7 @@ class Sql_Record_Collector implements Record_Collector_Interface {
[ $sql, $duration, $caller ] = $query_data;
+ /** @var float $query_start */
$query_start = $this->query_starts[ $key ] ?? $last_query_end;
$sql = trim( $sql );
$category = 'sql-read';
diff --git a/src/Record/Stopwatch_Record_Collector.php b/src/Record/Stopwatch_Record_Collector.php
index 91ac9e2..8e5aed7 100644
--- a/src/Record/Stopwatch_Record_Collector.php
+++ b/src/Record/Stopwatch_Record_Collector.php
@@ -52,6 +52,7 @@ class Stopwatch_Record_Collector implements Record_Collector_Interface {
$events = $this->stopwatch->getSectionEvents( '__root__' );
+ /** @var string $name */
foreach ( array_keys( $events ) as $name ) {
if ( $this->stopwatch->isStarted( $name ) ) {
unset( $events[ $name ] );
diff --git a/src/Record/Timeline_Iterator.php b/src/Record/Timeline_Iterator.php
index 213f2c7..ec5200f 100644
--- a/src/Record/Timeline_Iterator.php
+++ b/src/Record/Timeline_Iterator.php
@@ -5,6 +5,8 @@ namespace Rarst\Laps\Record;
/**
* Processes records into sets for display by template.
+ *
+ * @psalm-suppress PropertyNotSetInConstructor
*/
class Timeline_Iterator implements \Iterator {
@@ -22,6 +24,8 @@ class Timeline_Iterator implements \Iterator {
/**
* @param Recursive_Record_Iterator $iterator Record iterator.
+ *
+ * @psalm-suppress PossiblyFalsePropertyAssignmentValue
*/
public function __construct( Recursive_Record_Iterator $iterator ) {
@@ -36,6 +40,7 @@ class Timeline_Iterator implements \Iterator {
$data = [];
+ /** @var Record $record */
foreach ( $this->current as $record ) {
$data[] = $this->prepare( $record );
}