diff --git a/AGENTS.md b/AGENTS.md
index 0897e0a6..7b4c7ba3 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -27,6 +27,44 @@ Key constraints include:
* PER Coding Style (extending PSR-12).
* Strict type hinting for all parameters, return values, and properties.
+### Global function and constant references
+
+Inside a namespace, PHP resolves an unqualified function or constant name by first looking in the current namespace and only then falling back to the global namespace. That fallback is a runtime lookup on every call, and it prevents opcache from substituting the optimized handlers for common built-ins. Both `src/` and `tests/` are fully normalized to avoid it, and new code must stay that way.
+
+The rule is per file, based on how many times the name is referenced in that file:
+
+* **Referenced once:** prefix it with a leading backslash, e.g. `\gettype($value)` or `\PATHINFO_EXTENSION`.
+* **Referenced two or more times:** import it at the top with `use function` or `use const`, and leave the call sites unqualified.
+
+```php
+namespace WordPress\AiClient\Files\ValueObjects;
+
+use WordPress\AiClient\Common\Exception\InvalidArgumentException;
+
+use function sprintf;
+use function strtolower;
+
+// ...
+
+if (!\is_string($other)) { // used once: leading backslash
+ throw new InvalidArgumentException(
+ sprintf('Invalid MIME type: %s', \gettype($other)) // sprintf imported, gettype used once
+ );
+}
+
+return $this->value === strtolower($other);
+```
+
+Notes:
+
+* `composer phpcs` enforces the first half of this automatically. The `SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly` rule in `phpcs.xml.dist` fails the build on any global function or constant referenced via the namespace fallback, so a bare `sprintf(...)` is a hard error. It accepts both approved forms equally, so the choice between a leading backslash and an import is a convention that reviewers need to check by eye.
+* `composer phpcbf` can fix a fallback reference, but it always fixes by adding an import. For a name used only once, prefer prefixing with `\` by hand instead.
+* PSR-12 treats class imports, `use function` imports, and `use const` imports as separate header blocks, each separated by a blank line and each sorted alphabetically. `composer phpcbf` fixes the spacing automatically.
+* This applies to global **functions and constants** only. Classes need no equivalent treatment: PHP has no global fallback for class names, so a global class such as `Throwable` or `ReflectionClass` must already be imported or fully qualified for the code to run at all. Keep importing those with a plain `use` statement as usual.
+* `true`, `false`, and `null` are language constructs, not constants, and must not be prefixed.
+* Files with no namespace declaration, such as `cli.php` and `src/polyfills.php`, are already in the global namespace and need no qualification.
+* Do not qualify calls to functions defined by this project or by a dependency inside a namespace; the rule covers global built-ins (including the `src/polyfills.php` shims, which are defined globally).
+
## Core Principles
* **Provider Agnostic:** The client is designed to work with any AI provider, avoiding vendor lock-in.
@@ -79,6 +117,7 @@ For a more detailed overview, refer to the `docs/ARCHITECTURE.md` file.
* **Write Tests:** All new features or bug fixes must be accompanied by corresponding unit tests.
* **Use the Fluent API:** When writing examples or tests for the implementer API, prefer the fluent API for readability.
* **Use `{@inheritDoc}`:** When implementing an interface method, use `{@inheritDoc}` in the PHPDoc block to avoid duplicating documentation, as specified in `CONTRIBUTING.md`.
+* **Qualify Global Functions and Constants:** Within a namespace, prefix a global function or constant with `\` when it is referenced once in the file, or import it with `use function` / `use const` when it is referenced more than once. See "Global function and constant references" above.
### DON'T:
@@ -101,3 +140,4 @@ All exceptions must use the project's custom exception classes rather than PHP b
* **Direct HTTP Client Usage:** A common mistake is to instantiate a PSR-18 client directly in a model. This is incorrect. Instead, the model should receive an `HttpTransporter` instance and use it to send requests.
* **Ignoring the Fluent API:** While the traditional API is available, the fluent API is the preferred way for implementers to use the client. Avoid writing complex, nested method calls when the fluent API provides a cleaner alternative.
* **Duplicating Interface Documentation:** Manually writing PHPDoc descriptions for methods that implement an interface is a common pitfall. The `{@inheritDoc}` tag should be used instead to inherit the documentation from the interface.
+* **Unqualified Global Functions:** Writing `sprintf(...)` or `is_array(...)` bare inside a namespace is easy to do by habit, but it forces a runtime namespace fallback lookup on every call. Either prefix with `\` or add a `use function` import, depending on how many times the name appears in the file.
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 2e49db44..3bc464ec 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -40,4 +40,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AiClient.php b/src/AiClient.php
index 066bfa64..3b1d2116 100644
--- a/src/AiClient.php
+++ b/src/AiClient.php
@@ -19,6 +19,11 @@
use WordPress\AiClient\Results\DTO\EmbeddingResult;
use WordPress\AiClient\Results\DTO\GenerativeAiResult;
+use function get_class;
+use function gettype;
+use function is_object;
+use function sprintf;
+
/**
* Main AI Client class providing both fluent and traditional APIs for AI operations.
*
@@ -206,7 +211,7 @@ public static function isConfigured($availabilityOrIdOrClassName): bool
}
// Handle string input (provider ID or class name) via registry
- if (is_string($availabilityOrIdOrClassName)) {
+ if (\is_string($availabilityOrIdOrClassName)) {
return self::defaultRegistry()->isProviderConfigured($availabilityOrIdOrClassName);
}
diff --git a/src/Builders/EmbeddingBuilder.php b/src/Builders/EmbeddingBuilder.php
index 2cca2a02..eab6a2b7 100644
--- a/src/Builders/EmbeddingBuilder.php
+++ b/src/Builders/EmbeddingBuilder.php
@@ -21,6 +21,10 @@
use WordPress\AiClient\Results\DTO\Embedding;
use WordPress\AiClient\Results\DTO\EmbeddingResult;
+use function count;
+use function is_array;
+use function sprintf;
+
/**
* Fluent builder for generating embeddings.
*
@@ -71,7 +75,7 @@ public function __construct(
return;
}
- if (is_array($input) && array_is_list($input)) {
+ if (is_array($input) && \array_is_list($input)) {
/** @var list $input */
$this->withInput(...$input);
return;
@@ -256,8 +260,8 @@ private function parseInput($input): MessagePart
return $this->validatePart($input);
}
- if (is_string($input)) {
- if (trim($input) === '') {
+ if (\is_string($input)) {
+ if (\trim($input) === '') {
throw new InvalidArgumentException('Cannot create an embedding input from an empty string.');
}
return new MessagePart($input);
diff --git a/src/Builders/MessageBuilder.php b/src/Builders/MessageBuilder.php
index 6840c203..4a936dbf 100644
--- a/src/Builders/MessageBuilder.php
+++ b/src/Builders/MessageBuilder.php
@@ -55,7 +55,7 @@ public function __construct($input = null, ?MessageRoleEnum $role = null)
// Handle different input types
if ($input instanceof MessagePart) {
$this->parts[] = $input;
- } elseif (is_string($input)) {
+ } elseif (\is_string($input)) {
$this->withText($input);
} elseif ($input instanceof File) {
$this->withFile($input);
@@ -63,7 +63,7 @@ public function __construct($input = null, ?MessageRoleEnum $role = null)
$this->withFunctionCall($input);
} elseif ($input instanceof FunctionResponse) {
$this->withFunctionResponse($input);
- } elseif (is_array($input) && MessagePart::isArrayShape($input)) {
+ } elseif (\is_array($input) && MessagePart::isArrayShape($input)) {
$this->parts[] = MessagePart::fromArray($input);
} else {
throw new InvalidArgumentException(
@@ -141,7 +141,7 @@ public function usingModelRole(): self
*/
public function withText(string $text): self
{
- if (trim($text) === '') {
+ if (\trim($text) === '') {
throw new InvalidArgumentException('Text content cannot be empty.');
}
diff --git a/src/Builders/PromptBuilder.php b/src/Builders/PromptBuilder.php
index 538392db..09b20306 100644
--- a/src/Builders/PromptBuilder.php
+++ b/src/Builders/PromptBuilder.php
@@ -34,6 +34,13 @@
use WordPress\AiClient\Tools\DTO\FunctionResponse;
use WordPress\AiClient\Tools\DTO\WebSearch;
+use function array_is_list;
+use function array_merge;
+use function end;
+use function is_array;
+use function is_string;
+use function sprintf;
+
/**
* Fluent builder for constructing AI prompts.
*
@@ -536,7 +543,7 @@ private function inferCapabilityFromOutputModalities(): CapabilityEnum
// Multi-modal output (multiple modalities) defaults to text generation. This is temporary
// as a multi-modal interface will be implemented in the future.
- if (count($outputModalities) > 1) {
+ if (\count($outputModalities) > 1) {
return CapabilityEnum::textGeneration();
}
@@ -1114,7 +1121,7 @@ protected function appendPartToMessages(MessagePart $part): void
if ($lastMessage instanceof Message && $lastMessage->getRole()->isUser()) {
// Replace the last message with a new one containing the appended part
- array_pop($this->messages);
+ \array_pop($this->messages);
$this->messages[] = $lastMessage->withPart($part);
return;
}
@@ -1166,7 +1173,7 @@ private function parseMessage($input, MessageRoleEnum $defaultRole): Message
// Handle string input
if (is_string($input)) {
- if (trim($input) === '') {
+ if (\trim($input) === '') {
throw new InvalidArgumentException('Cannot create a message from an empty string.');
}
return new Message($defaultRole, [new MessagePart($input)]);
@@ -1242,7 +1249,7 @@ private function validateMessages(): void
);
}
- $firstMessage = reset($messages);
+ $firstMessage = \reset($messages);
if (!$firstMessage->getRole()->isUser()) {
throw new InvalidArgumentException(
'The first message must be from a user role, not from ' . $firstMessage->getRole()->value
diff --git a/src/Builders/Traits/ModelResolutionTrait.php b/src/Builders/Traits/ModelResolutionTrait.php
index 08780903..56895935 100644
--- a/src/Builders/Traits/ModelResolutionTrait.php
+++ b/src/Builders/Traits/ModelResolutionTrait.php
@@ -10,6 +10,8 @@
use WordPress\AiClient\Providers\Models\Contracts\ModelInterface;
use WordPress\AiClient\Providers\Models\DTO\ModelConfig;
+use function array_merge;
+
/**
* Provides shared model selection and configuration methods for builders.
*
diff --git a/src/Common/AbstractDataTransferObject.php b/src/Common/AbstractDataTransferObject.php
index 0029ca5f..9328cc24 100644
--- a/src/Common/AbstractDataTransferObject.php
+++ b/src/Common/AbstractDataTransferObject.php
@@ -10,6 +10,8 @@
use WordPress\AiClient\Common\Contracts\WithJsonSchemaInterface;
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
+use function is_array;
+
/**
* Abstract base class for all Data Value Objects in the AI Client.
*
@@ -46,17 +48,17 @@ protected static function validateFromArrayData(array $data, array $requiredKeys
$missingKeys = [];
foreach ($requiredKeys as $key) {
- if (!array_key_exists($key, $data)) {
+ if (!\array_key_exists($key, $data)) {
$missingKeys[] = $key;
}
}
if (!empty($missingKeys)) {
throw new InvalidArgumentException(
- sprintf(
+ \sprintf(
'%s::fromArray() missing required keys: %s',
static::class,
- implode(', ', $missingKeys)
+ \implode(', ', $missingKeys)
)
);
}
diff --git a/src/Common/AbstractEnum.php b/src/Common/AbstractEnum.php
index 39d92af6..33c1f176 100644
--- a/src/Common/AbstractEnum.php
+++ b/src/Common/AbstractEnum.php
@@ -10,6 +10,9 @@
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
use WordPress\AiClient\Common\Exception\RuntimeException;
+use function sprintf;
+use function strtoupper;
+
/**
* Abstract base class for enum-like behavior in PHP 7.4.
*
@@ -204,7 +207,7 @@ final public function is(self $other): bool
*/
final public static function getValues(): array
{
- return array_values(static::getConstants());
+ return \array_values(static::getConstants());
}
/**
@@ -217,7 +220,7 @@ final public static function getValues(): array
*/
final public static function isValidValue(string $value): bool
{
- return in_array($value, self::getValues(), true);
+ return \in_array($value, self::getValues(), true);
}
/**
@@ -286,7 +289,7 @@ protected static function determineClassEnumerations(string $className): array
$enumConstants = [];
foreach ($constants as $name => $value) {
// Check if constant name follows uppercase snake_case pattern
- if (!preg_match('/^[A-Z][A-Z0-9_]*$/', $name)) {
+ if (!\preg_match('/^[A-Z][A-Z0-9_]*$/', $name)) {
throw new RuntimeException(
sprintf(
'Invalid enum constant name "%s" in %s. Constants must be UPPER_SNAKE_CASE.',
@@ -297,14 +300,14 @@ protected static function determineClassEnumerations(string $className): array
}
// Check if value is valid type
- if (!is_string($value)) {
+ if (!\is_string($value)) {
throw new RuntimeException(
sprintf(
'Invalid enum value type for constant %s::%s. ' .
'Only string values are allowed, %s given.',
$className,
$name,
- gettype($value)
+ \gettype($value)
)
);
}
@@ -328,8 +331,8 @@ protected static function determineClassEnumerations(string $className): array
final public function __call(string $name, array $arguments): bool
{
// Handle is* methods
- if (str_starts_with($name, 'is')) {
- $constantName = self::camelCaseToConstant(substr($name, 2));
+ if (\str_starts_with($name, 'is')) {
+ $constantName = self::camelCaseToConstant(\substr($name, 2));
$constants = static::getConstants();
if (isset($constants[$constantName])) {
@@ -376,7 +379,7 @@ final public static function __callStatic(string $name, array $arguments): self
*/
private static function camelCaseToConstant(string $camelCase): string
{
- $snakeCase = preg_replace('/([a-z])([A-Z])/', '$1_$2', $camelCase);
+ $snakeCase = \preg_replace('/([a-z])([A-Z])/', '$1_$2', $camelCase);
if ($snakeCase === null) {
return strtoupper($camelCase);
}
diff --git a/src/Common/Traits/WithDataCachingTrait.php b/src/Common/Traits/WithDataCachingTrait.php
index ab11ba1c..67d48013 100644
--- a/src/Common/Traits/WithDataCachingTrait.php
+++ b/src/Common/Traits/WithDataCachingTrait.php
@@ -63,7 +63,7 @@ protected function hasCache(string $key): bool
return $cache->has($fullKey);
}
- return array_key_exists($fullKey, $this->localCache);
+ return \array_key_exists($fullKey, $this->localCache);
}
/**
diff --git a/src/Files/DTO/File.php b/src/Files/DTO/File.php
index e17b7418..e54ba915 100644
--- a/src/Files/DTO/File.php
+++ b/src/Files/DTO/File.php
@@ -10,6 +10,9 @@
use WordPress\AiClient\Files\Enums\FileTypeEnum;
use WordPress\AiClient\Files\ValueObjects\MimeType;
+use function preg_match;
+use function sprintf;
+
/**
* Represents a file in the AI client.
*
@@ -101,7 +104,7 @@ private function detectAndProcessFile(string $file, ?string $providedMimeType):
}
// Check if it's a local file path (before base64 check)
- if (file_exists($file) && is_file($file)) {
+ if (\file_exists($file) && \is_file($file)) {
$this->fileType = FileTypeEnum::inline();
$this->base64Data = $this->convertFileToBase64($file);
$this->mimeType = $this->determineMimeType($providedMimeType, null, $file);
@@ -136,7 +139,7 @@ private function detectAndProcessFile(string $file, ?string $providedMimeType):
*/
private function isUrl(string $string): bool
{
- return filter_var($string, FILTER_VALIDATE_URL) !== false
+ return \filter_var($string, \FILTER_VALIDATE_URL) !== false
&& preg_match('/^https?:\/\//i', $string);
}
@@ -151,7 +154,7 @@ private function isUrl(string $string): bool
*/
private function convertFileToBase64(string $filePath): string
{
- $fileContent = @file_get_contents($filePath);
+ $fileContent = @\file_get_contents($filePath);
if ($fileContent === false) {
throw new RuntimeException(
@@ -159,7 +162,7 @@ private function convertFileToBase64(string $filePath): string
);
}
- return base64_encode($fileContent);
+ return \base64_encode($fileContent);
}
/**
@@ -364,16 +367,16 @@ private function determineMimeType(
// Try to determine from file extension
if ($pathOrUrl !== null) {
- $parsedUrl = parse_url($pathOrUrl);
+ $parsedUrl = \parse_url($pathOrUrl);
$path = $parsedUrl['path'] ?? $pathOrUrl;
// Remove query string and fragment if present
- $cleanPath = strtok($path, '?#');
+ $cleanPath = \strtok($path, '?#');
if ($cleanPath === false) {
$cleanPath = $path;
}
- $extension = pathinfo($cleanPath, PATHINFO_EXTENSION);
+ $extension = \pathinfo($cleanPath, \PATHINFO_EXTENSION);
if (!empty($extension)) {
try {
return MimeType::fromExtension($extension);
diff --git a/src/Files/ValueObjects/MimeType.php b/src/Files/ValueObjects/MimeType.php
index ac95deed..d06de137 100644
--- a/src/Files/ValueObjects/MimeType.php
+++ b/src/Files/ValueObjects/MimeType.php
@@ -6,6 +6,9 @@
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
+use function sprintf;
+use function strtolower;
+
/**
* Value object representing a MIME type.
*
@@ -142,7 +145,7 @@ public function __construct(string $value)
public function toExtension(): string
{
// Reverse lookup for the MIME type to find the extension.
- $extension = array_search($this->value, self::$extensionMap, true);
+ $extension = \array_search($this->value, self::$extensionMap, true);
if ($extension === false) {
throw new InvalidArgumentException(
sprintf('No known extension for MIME type: %s', $this->value)
@@ -185,7 +188,7 @@ public static function fromExtension(string $extension): self
public static function isValid(string $mimeType): bool
{
// Basic MIME type validation: type/subtype
- return (bool) preg_match(
+ return (bool) \preg_match(
'/^[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_+.]*$/',
$mimeType
);
@@ -204,7 +207,7 @@ public static function isValid(string $mimeType): bool
*/
public function isType(string $mimeType): bool
{
- return str_starts_with($this->value, strtolower($mimeType) . '/');
+ return \str_starts_with($this->value, strtolower($mimeType) . '/');
}
/**
@@ -264,7 +267,7 @@ public function isText(): bool
*/
public function isDocument(): bool
{
- return in_array($this->value, self::$documentTypes, true);
+ return \in_array($this->value, self::$documentTypes, true);
}
/**
@@ -282,12 +285,12 @@ public function equals($other): bool
return $this->value === $other->value;
}
- if (is_string($other)) {
+ if (\is_string($other)) {
return $this->value === strtolower($other);
}
throw new InvalidArgumentException(
- sprintf('Invalid MIME type comparison: %s', gettype($other))
+ sprintf('Invalid MIME type comparison: %s', \gettype($other))
);
}
diff --git a/src/Messages/DTO/Message.php b/src/Messages/DTO/Message.php
index 86ad4bc1..c8bb9214 100644
--- a/src/Messages/DTO/Message.php
+++ b/src/Messages/DTO/Message.php
@@ -8,6 +8,8 @@
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
use WordPress\AiClient\Messages\Enums\MessageRoleEnum;
+use function array_map;
+
/**
* Represents a message in an AI conversation.
*
diff --git a/src/Messages/DTO/MessagePart.php b/src/Messages/DTO/MessagePart.php
index 228471be..ce4a59b0 100644
--- a/src/Messages/DTO/MessagePart.php
+++ b/src/Messages/DTO/MessagePart.php
@@ -97,7 +97,7 @@ public function __construct($content, ?MessagePartChannelEnum $channel = null, ?
$this->channel = $channel ?? MessagePartChannelEnum::content();
$this->thoughtSignature = $thoughtSignature;
- if (is_string($content)) {
+ if (\is_string($content)) {
$this->type = MessagePartTypeEnum::text();
$this->text = $content;
} elseif ($content instanceof File) {
@@ -110,9 +110,9 @@ public function __construct($content, ?MessagePartChannelEnum $channel = null, ?
$this->type = MessagePartTypeEnum::functionResponse();
$this->functionResponse = $content;
} else {
- $type = is_object($content) ? get_class($content) : gettype($content);
+ $type = \is_object($content) ? \get_class($content) : \gettype($content);
throw new InvalidArgumentException(
- sprintf(
+ \sprintf(
'Unsupported content type %s. Expected string, File, '
. 'FunctionCall, or FunctionResponse.',
$type
diff --git a/src/Messages/Util/ModalityCombinationsUtil.php b/src/Messages/Util/ModalityCombinationsUtil.php
index e9ad1a1c..78b8874d 100644
--- a/src/Messages/Util/ModalityCombinationsUtil.php
+++ b/src/Messages/Util/ModalityCombinationsUtil.php
@@ -33,7 +33,7 @@ class ModalityCombinationsUtil
public static function buildCombinations(array $required, array $optional): array
{
$combinations = [];
- $count = count($optional);
+ $count = \count($optional);
$subsetCount = 1 << $count; // 2^count.
for ($i = 0; $i < $subsetCount; $i++) {
diff --git a/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php b/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php
index 52c0cd5f..5db56c1f 100644
--- a/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php
+++ b/src/Providers/ApiBasedImplementation/AbstractApiBasedModelMetadataDirectory.php
@@ -47,7 +47,7 @@ abstract class AbstractApiBasedModelMetadataDirectory implements
final public function listModelMetadata(): array
{
$modelsMetadata = $this->getModelMetadataMap();
- return array_values($modelsMetadata);
+ return \array_values($modelsMetadata);
}
/**
@@ -71,7 +71,7 @@ final public function getModelMetadata(string $modelId): ModelMetadata
$modelsMetadata = $this->getModelMetadataMap();
if (!isset($modelsMetadata[$modelId])) {
throw new InvalidArgumentException(
- sprintf('No model with ID %s was found in the provider', $modelId)
+ \sprintf('No model with ID %s was found in the provider', $modelId)
);
}
return $modelsMetadata[$modelId];
@@ -111,7 +111,7 @@ protected function getCachedKeys(): array
*/
protected function getBaseCacheKey(): string
{
- return 'ai_client_' . AiClient::VERSION . '_' . md5(static::class);
+ return 'ai_client_' . AiClient::VERSION . '_' . \md5(static::class);
}
/**
diff --git a/src/Providers/ApiBasedImplementation/AbstractApiProvider.php b/src/Providers/ApiBasedImplementation/AbstractApiProvider.php
index 3b5d3658..08705982 100644
--- a/src/Providers/ApiBasedImplementation/AbstractApiProvider.php
+++ b/src/Providers/ApiBasedImplementation/AbstractApiProvider.php
@@ -48,6 +48,6 @@ public static function url(string $path = ''): string
return static::baseUrl();
}
- return static::baseUrl() . '/' . ltrim($path, '/');
+ return static::baseUrl() . '/' . \ltrim($path, '/');
}
}
diff --git a/src/Providers/DTO/ProviderMetadata.php b/src/Providers/DTO/ProviderMetadata.php
index a19e6d56..815c0827 100644
--- a/src/Providers/DTO/ProviderMetadata.php
+++ b/src/Providers/DTO/ProviderMetadata.php
@@ -101,9 +101,9 @@ public function __construct(
?string $description = null,
?string $logoPath = null
) {
- if (!preg_match('/^[a-z0-9\-_]+$/', $id)) {
+ if (!\preg_match('/^[a-z0-9\-_]+$/', $id)) {
throw new InvalidArgumentException(
- sprintf(
+ \sprintf(
// phpcs:ignore Generic.Files.LineLength.TooLong
'Invalid provider ID "%s". Only lowercase alphanumeric characters, hyphens, and underscores are allowed.',
$id
@@ -239,7 +239,7 @@ public static function getJsonSchema(): array
],
self::KEY_AUTHENTICATION_METHOD => [
'type' => ['string', 'null'],
- 'enum' => array_merge(RequestAuthenticationMethod::getValues(), [null]),
+ 'enum' => \array_merge(RequestAuthenticationMethod::getValues(), [null]),
'description' => 'The authentication method.',
],
self::KEY_LOGO_PATH => [
diff --git a/src/Providers/DTO/ProviderModelsMetadata.php b/src/Providers/DTO/ProviderModelsMetadata.php
index 9e3b0f9c..70222cf0 100644
--- a/src/Providers/DTO/ProviderModelsMetadata.php
+++ b/src/Providers/DTO/ProviderModelsMetadata.php
@@ -8,6 +8,8 @@
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
use WordPress\AiClient\Providers\Models\DTO\ModelMetadata;
+use function array_map;
+
/**
* Represents metadata about a provider and its available models.
*
@@ -53,7 +55,7 @@ class ProviderModelsMetadata extends AbstractDataTransferObject
*/
public function __construct(ProviderMetadata $provider, array $models)
{
- if (!array_is_list($models)) {
+ if (!\array_is_list($models)) {
throw new InvalidArgumentException('Models must be a list array.');
}
diff --git a/src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.php b/src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.php
index f14b36ee..cbd5991e 100644
--- a/src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.php
+++ b/src/Providers/Http/Abstracts/AbstractClientDiscoveryStrategy.php
@@ -30,7 +30,7 @@ abstract class AbstractClientDiscoveryStrategy implements DiscoveryStrategy
*/
public static function init(): void
{
- if (!class_exists('\Http\Discovery\Psr18ClientDiscovery')) {
+ if (!\class_exists('\Http\Discovery\Psr18ClientDiscovery')) {
return;
}
@@ -67,7 +67,7 @@ public static function getCandidates($type)
'Psr\Http\Message\UriFactoryInterface',
];
- if (in_array($type, $psr17Factories, true)) {
+ if (\in_array($type, $psr17Factories, true)) {
return [
[
'class' => Psr17Factory::class,
diff --git a/src/Providers/Http/Collections/HeadersCollection.php b/src/Providers/Http/Collections/HeadersCollection.php
index 9a211bbb..29096095 100644
--- a/src/Providers/Http/Collections/HeadersCollection.php
+++ b/src/Providers/Http/Collections/HeadersCollection.php
@@ -4,6 +4,8 @@
namespace WordPress\AiClient\Providers\Http\Collections;
+use function strtolower;
+
/**
* Simple collection for managing HTTP headers with case-insensitive access.
*
@@ -80,7 +82,7 @@ public function getAll(): array
public function getAsString(string $name): ?string
{
$values = $this->get($name);
- return $values !== null ? implode(', ', $values) : null;
+ return $values !== null ? \implode(', ', $values) : null;
}
/**
@@ -107,11 +109,11 @@ public function has(string $name): bool
*/
private function set(string $name, $value): void
{
- if (is_array($value)) {
- $normalizedValues = array_values($value);
+ if (\is_array($value)) {
+ $normalizedValues = \array_values($value);
} else {
// Split comma-separated string into array
- $normalizedValues = array_map('trim', explode(',', $value));
+ $normalizedValues = \array_map('trim', \explode(',', $value));
}
$lowerName = strtolower($name);
diff --git a/src/Providers/Http/DTO/Request.php b/src/Providers/Http/DTO/Request.php
index 4dafd3de..7afa8fe6 100644
--- a/src/Providers/Http/DTO/Request.php
+++ b/src/Providers/Http/DTO/Request.php
@@ -11,6 +11,10 @@
use WordPress\AiClient\Providers\Http\Collections\HeadersCollection;
use WordPress\AiClient\Providers\Http\Enums\HttpMethodEnum;
+use function http_build_query;
+use function is_array;
+use function is_string;
+
/**
* Represents an HTTP request.
*
@@ -153,7 +157,7 @@ public function getUri(): string
{
// If GET request with data, append as query parameters
if ($this->method === HttpMethodEnum::GET() && $this->data !== null && !empty($this->data)) {
- $separator = str_contains($this->uri, '?') ? '&' : '?';
+ $separator = \str_contains($this->uri, '?') ? '&' : '?';
return $this->uri . $separator . http_build_query($this->data);
}
@@ -242,8 +246,8 @@ public function getBody(): ?string
$contentType = $this->getContentType();
// JSON encoding
- if ($contentType !== null && stripos($contentType, 'application/json') !== false) {
- return json_encode($this->data, JSON_THROW_ON_ERROR);
+ if ($contentType !== null && \stripos($contentType, 'application/json') !== false) {
+ return \json_encode($this->data, \JSON_THROW_ON_ERROR);
}
// Default to URL encoding for forms
diff --git a/src/Providers/Http/DTO/RequestOptions.php b/src/Providers/Http/DTO/RequestOptions.php
index 9b101bef..b66332a4 100644
--- a/src/Providers/Http/DTO/RequestOptions.php
+++ b/src/Providers/Http/DTO/RequestOptions.php
@@ -247,7 +247,7 @@ private function validateTimeout(?float $value, string $fieldName): void
{
if ($value !== null && $value < 0) {
throw new InvalidArgumentException(
- sprintf('Request option "%s" must be greater than or equal to 0.', $fieldName)
+ \sprintf('Request option "%s" must be greater than or equal to 0.', $fieldName)
);
}
}
diff --git a/src/Providers/Http/DTO/Response.php b/src/Providers/Http/DTO/Response.php
index 623ab770..9def154f 100644
--- a/src/Providers/Http/DTO/Response.php
+++ b/src/Providers/Http/DTO/Response.php
@@ -185,14 +185,14 @@ public function getData(): ?array
return null;
}
- $data = json_decode($this->body, true);
+ $data = \json_decode($this->body, true);
- if (json_last_error() !== JSON_ERROR_NONE) {
+ if (\json_last_error() !== \JSON_ERROR_NONE) {
return null;
}
/** @var array|null $data */
- return is_array($data) ? $data : null;
+ return \is_array($data) ? $data : null;
}
/**
diff --git a/src/Providers/Http/Enums/HttpMethodEnum.php b/src/Providers/Http/Enums/HttpMethodEnum.php
index 8ecad16a..f08a781a 100644
--- a/src/Providers/Http/Enums/HttpMethodEnum.php
+++ b/src/Providers/Http/Enums/HttpMethodEnum.php
@@ -6,6 +6,8 @@
use WordPress\AiClient\Common\AbstractEnum;
+use function in_array;
+
/**
* Represents HTTP request methods.
*
diff --git a/src/Providers/Http/Exception/ClientException.php b/src/Providers/Http/Exception/ClientException.php
index 0429c8f5..90964beb 100644
--- a/src/Providers/Http/Exception/ClientException.php
+++ b/src/Providers/Http/Exception/ClientException.php
@@ -9,6 +9,8 @@
use WordPress\AiClient\Providers\Http\DTO\Response;
use WordPress\AiClient\Providers\Http\Util\ErrorMessageExtractor;
+use function sprintf;
+
/**
* Exception thrown for 4xx HTTP client errors.
*
diff --git a/src/Providers/Http/Exception/NetworkException.php b/src/Providers/Http/Exception/NetworkException.php
index ecfa3d49..f8dcb689 100644
--- a/src/Providers/Http/Exception/NetworkException.php
+++ b/src/Providers/Http/Exception/NetworkException.php
@@ -57,7 +57,7 @@ public function getRequest(): Request
public static function fromPsr18NetworkException(RequestInterface $psrRequest, \Throwable $networkException): self
{
$request = Request::fromPsrRequest($psrRequest);
- $message = sprintf(
+ $message = \sprintf(
'Network error occurred while sending request to %s: %s',
$request->getUri(),
$networkException->getMessage()
diff --git a/src/Providers/Http/Exception/RedirectException.php b/src/Providers/Http/Exception/RedirectException.php
index 57da329d..80697821 100644
--- a/src/Providers/Http/Exception/RedirectException.php
+++ b/src/Providers/Http/Exception/RedirectException.php
@@ -7,6 +7,8 @@
use WordPress\AiClient\Common\Exception\RuntimeException;
use WordPress\AiClient\Providers\Http\DTO\Response;
+use function sprintf;
+
/**
* Exception thrown for 3xx HTTP redirect responses.
*
diff --git a/src/Providers/Http/Exception/ResponseException.php b/src/Providers/Http/Exception/ResponseException.php
index 01e2bd70..b6724c27 100644
--- a/src/Providers/Http/Exception/ResponseException.php
+++ b/src/Providers/Http/Exception/ResponseException.php
@@ -6,6 +6,8 @@
use WordPress\AiClient\Common\Exception\RuntimeException;
+use function sprintf;
+
/**
* Exception class for HTTP response errors.
*
diff --git a/src/Providers/Http/Exception/ServerException.php b/src/Providers/Http/Exception/ServerException.php
index bc4b63de..5fa0e26c 100644
--- a/src/Providers/Http/Exception/ServerException.php
+++ b/src/Providers/Http/Exception/ServerException.php
@@ -8,6 +8,8 @@
use WordPress\AiClient\Providers\Http\DTO\Response;
use WordPress\AiClient\Providers\Http\Util\ErrorMessageExtractor;
+use function sprintf;
+
/**
* Exception thrown for 5xx HTTP server errors.
*
diff --git a/src/Providers/Http/HttpTransporter.php b/src/Providers/Http/HttpTransporter.php
index 00917cec..c1b992c1 100644
--- a/src/Providers/Http/HttpTransporter.php
+++ b/src/Providers/Http/HttpTransporter.php
@@ -91,7 +91,7 @@ public function send(Request $request, ?RequestOptions $options = null): Respons
} catch (\Psr\Http\Client\ClientExceptionInterface $e) {
// Handle other PSR-18 client exceptions that are not network-related
throw new RuntimeException(
- sprintf(
+ \sprintf(
'HTTP client error occurred while sending request to %s: %s',
$request->getUri(),
$e->getMessage()
@@ -173,7 +173,7 @@ private function isGuzzleClient(ClientInterface $client): bool
{
$reflection = new \ReflectionObject($client);
- if (!is_callable([$client, 'send'])) {
+ if (!\is_callable([$client, 'send'])) {
return false;
}
@@ -189,7 +189,7 @@ private function isGuzzleClient(ClientInterface $client): bool
$parameters = $method->getParameters();
- if (count($parameters) < 2) {
+ if (\count($parameters) < 2) {
return false;
}
@@ -198,7 +198,7 @@ private function isGuzzleClient(ClientInterface $client): bool
return false;
}
- if (!is_a($firstParameter->getName(), RequestInterface::class, true)) {
+ if (!\is_a($firstParameter->getName(), RequestInterface::class, true)) {
return false;
}
diff --git a/src/Providers/Http/Util/ErrorMessageExtractor.php b/src/Providers/Http/Util/ErrorMessageExtractor.php
index c31cd5b7..18a9de44 100644
--- a/src/Providers/Http/Util/ErrorMessageExtractor.php
+++ b/src/Providers/Http/Util/ErrorMessageExtractor.php
@@ -4,6 +4,9 @@
namespace WordPress\AiClient\Providers\Http\Util;
+use function is_array;
+use function is_string;
+
/**
* Utility for extracting error messages from API response data.
*
diff --git a/src/Providers/Http/Util/ResponseUtil.php b/src/Providers/Http/Util/ResponseUtil.php
index 18177bed..0c28dbd8 100644
--- a/src/Providers/Http/Util/ResponseUtil.php
+++ b/src/Providers/Http/Util/ResponseUtil.php
@@ -58,7 +58,7 @@ public static function throwIfNotSuccessful(Response $response): void
}
throw new \RuntimeException(
- sprintf('Response returned invalid status code: %s', $response->getStatusCode())
+ \sprintf('Response returned invalid status code: %s', $response->getStatusCode())
);
}
}
diff --git a/src/Providers/ModelResolver.php b/src/Providers/ModelResolver.php
index c8aeefe5..36388cdd 100644
--- a/src/Providers/ModelResolver.php
+++ b/src/Providers/ModelResolver.php
@@ -12,6 +12,10 @@
use WordPress\AiClient\Providers\Models\DTO\ModelMetadata;
use WordPress\AiClient\Providers\Models\DTO\ModelRequirements;
+use function is_string;
+use function reset;
+use function sprintf;
+
/**
* Resolves the concrete AI model to use based on selection preferences.
*
@@ -124,9 +128,9 @@ public function setModelPreferences(...$preferredModels): void
$preferenceKeys = [];
foreach ($preferredModels as $preferredModel) {
- if (is_array($preferredModel)) {
+ if (\is_array($preferredModel)) {
// [model identifier, provider ID] tuple
- if (!array_is_list($preferredModel) || count($preferredModel) !== 2) {
+ if (!\array_is_list($preferredModel) || \count($preferredModel) !== 2) {
throw new InvalidArgumentException(
'Model preference tuple must contain model identifier and provider ID.'
);
@@ -277,14 +281,14 @@ public function resolve(
// Check if any preferred models match the candidates, in priority order.
if (!empty($this->modelPreferenceKeys)) {
// Find preferences that match available candidates, preserving preference order.
- $matchingPreferences = array_intersect_key(
- array_flip($this->modelPreferenceKeys),
+ $matchingPreferences = \array_intersect_key(
+ \array_flip($this->modelPreferenceKeys),
$candidateMap
);
if (!empty($matchingPreferences)) {
// Get the first matching preference key
- $firstMatchKey = key($matchingPreferences);
+ $firstMatchKey = \key($matchingPreferences);
[$providerId, $modelId] = $candidateMap[$firstMatchKey];
$model = $this->registry->getProviderModel($providerId, $modelId, $modelConfig);
@@ -428,7 +432,7 @@ private function normalizePreferenceIdentifier(
throw new InvalidArgumentException($emptyMessage);
}
- $trimmed = trim($value);
+ $trimmed = \trim($value);
if ($trimmed === '') {
throw new InvalidArgumentException($emptyMessage);
}
diff --git a/src/Providers/Models/DTO/ModelConfig.php b/src/Providers/Models/DTO/ModelConfig.php
index fad995d0..411f1399 100644
--- a/src/Providers/Models/DTO/ModelConfig.php
+++ b/src/Providers/Models/DTO/ModelConfig.php
@@ -12,6 +12,9 @@
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
use WordPress\AiClient\Tools\DTO\WebSearch;
+use function array_is_list;
+use function array_map;
+
/**
* Represents configuration for an AI model.
*
@@ -698,7 +701,7 @@ public function getOutputMediaOrientation(): ?MediaOrientationEnum
*/
public function setOutputMediaAspectRatio(string $outputMediaAspectRatio): void
{
- if (!preg_match('/^\d+:\d+$/', $outputMediaAspectRatio)) {
+ if (!\preg_match('/^\d+:\d+$/', $outputMediaAspectRatio)) {
throw new InvalidArgumentException(
'Output media aspect ratio must be in the format "width:height" (e.g. 3:2, 16:9).'
);
@@ -736,7 +739,7 @@ protected function validateMediaOrientationAspectRatioCompatibility(
MediaOrientationEnum $orientation,
string $aspectRatio
): void {
- $aspectRatioParts = explode(':', $aspectRatio);
+ $aspectRatioParts = \explode(':', $aspectRatio);
if ($orientation->isSquare() && $aspectRatioParts[0] !== $aspectRatioParts[1]) {
throw new InvalidArgumentException(
'The aspect ratio "' . $aspectRatio . '" is not compatible with the square orientation.'
diff --git a/src/Providers/Models/DTO/ModelMetadata.php b/src/Providers/Models/DTO/ModelMetadata.php
index 529f090f..d84a1ac5 100644
--- a/src/Providers/Models/DTO/ModelMetadata.php
+++ b/src/Providers/Models/DTO/ModelMetadata.php
@@ -8,6 +8,9 @@
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum;
+use function array_is_list;
+use function array_map;
+
/**
* Represents metadata about an AI model.
*
diff --git a/src/Providers/Models/DTO/ModelRequirements.php b/src/Providers/Models/DTO/ModelRequirements.php
index 492e5fd8..5d0095ae 100644
--- a/src/Providers/Models/DTO/ModelRequirements.php
+++ b/src/Providers/Models/DTO/ModelRequirements.php
@@ -12,6 +12,13 @@
use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum;
use WordPress\AiClient\Providers\Models\Enums\OptionEnum;
+use function array_is_list;
+use function array_map;
+use function array_unique;
+use function array_values;
+
+use const SORT_REGULAR;
+
/**
* Represents requirements that implementing code has for AI model selection.
*
@@ -155,7 +162,7 @@ public static function fromPromptData(CapabilityEnum $capability, array $message
$inputModalities = [];
// Check if we have chat history (multiple messages)
- if (count($messages) > 1) {
+ if (\count($messages) > 1) {
$capabilities[] = CapabilityEnum::chatHistory();
}
diff --git a/src/Providers/Models/DTO/SupportedOption.php b/src/Providers/Models/DTO/SupportedOption.php
index 3a0e25d6..cca301e9 100644
--- a/src/Providers/Models/DTO/SupportedOption.php
+++ b/src/Providers/Models/DTO/SupportedOption.php
@@ -9,6 +9,8 @@
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
use WordPress\AiClient\Providers\Models\Enums\OptionEnum;
+use function is_array;
+
/**
* Represents a supported configuration option for an AI model.
*
@@ -51,7 +53,7 @@ class SupportedOption extends AbstractDataTransferObject
*/
public function __construct(OptionEnum $name, ?array $supportedValues = null)
{
- if ($supportedValues !== null && !array_is_list($supportedValues)) {
+ if ($supportedValues !== null && !\array_is_list($supportedValues)) {
throw new InvalidArgumentException('Supported values must be a list array.');
}
@@ -144,8 +146,8 @@ private static function normalizeValue($value)
*/
private static function normalizeArrayForComparison(array $items): array
{
- $normalized = array_map([self::class, 'normalizeValue'], $items);
- sort($normalized);
+ $normalized = \array_map([self::class, 'normalizeValue'], $items);
+ \sort($normalized);
return $normalized;
}
diff --git a/src/Providers/Models/Enums/OptionEnum.php b/src/Providers/Models/Enums/OptionEnum.php
index dde22ae2..c73a9891 100644
--- a/src/Providers/Models/Enums/OptionEnum.php
+++ b/src/Providers/Models/Enums/OptionEnum.php
@@ -99,13 +99,13 @@ protected static function determineClassEnumerations(string $className): array
// Add ModelConfig constants that start with KEY_
foreach ($modelConfigConstants as $constantName => $constantValue) {
- if (str_starts_with($constantName, 'KEY_')) {
+ if (\str_starts_with($constantName, 'KEY_')) {
// Remove KEY_ prefix to get the enum constant name
- $enumConstantName = substr($constantName, 4);
+ $enumConstantName = \substr($constantName, 4);
// The value is the snake_case version stored in ModelConfig
// ModelConfig already stores these as snake_case strings
- if (is_string($constantValue)) {
+ if (\is_string($constantValue)) {
$constants[$enumConstantName] = $constantValue;
}
}
diff --git a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php
index 482e9909..84be27ed 100644
--- a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php
+++ b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModel.php
@@ -23,6 +23,9 @@
use WordPress\AiClient\Results\DTO\TokenUsage;
use WordPress\AiClient\Results\Enums\FinishReasonEnum;
+use function is_array;
+use function is_string;
+
/**
* Base class for an image generation model for providers that implement OpenAI's API format.
*
@@ -125,7 +128,7 @@ protected function prepareGenerateImageParams(array $prompt): array
$outputMimeType = $config->getOutputMimeType();
if ($outputMimeType !== null) {
- $params['output_format'] = preg_replace('/^image\//', '', $outputMimeType);
+ $params['output_format'] = \preg_replace('/^image\//', '', $outputMimeType);
}
$outputMediaOrientation = $config->getOutputMediaOrientation();
@@ -142,7 +145,7 @@ protected function prepareGenerateImageParams(array $prompt): array
foreach ($customOptions as $key => $value) {
if (isset($params[$key])) {
throw new InvalidArgumentException(
- sprintf(
+ \sprintf(
'The custom option "%s" conflicts with an existing parameter.',
$key
)
@@ -166,7 +169,7 @@ protected function prepareGenerateImageParams(array $prompt): array
*/
protected function preparePromptParam(array $messages): string
{
- if (count($messages) !== 1) {
+ if (\count($messages) !== 1) {
throw new InvalidArgumentException(
'The API requires a single user message as prompt.'
);
@@ -304,7 +307,7 @@ protected function parseResponseToGenerativeAiResult(
$candidates = [];
foreach ($responseData['data'] as $index => $choiceData) {
- if (!is_array($choiceData) || array_is_list($choiceData)) {
+ if (!is_array($choiceData) || \array_is_list($choiceData)) {
throw ResponseException::fromInvalidData(
$this->providerMetadata()->getName(),
"data[{$index}]",
diff --git a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php
index e0e2e71b..7669a292 100644
--- a/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php
+++ b/src/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModel.php
@@ -25,6 +25,16 @@
use WordPress\AiClient\Tools\DTO\FunctionCall;
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
+use function array_filter;
+use function array_is_list;
+use function array_map;
+use function array_values;
+use function count;
+use function is_array;
+use function is_string;
+use function json_encode;
+use function sprintf;
+
/**
* Base class for a text generation model for providers that implement OpenAI's API format.
*
@@ -247,7 +257,7 @@ function (Message $message): array {
);
if ($systemInstruction) {
- array_unshift(
+ \array_unshift(
$messagesParam,
[
/*
@@ -766,7 +776,7 @@ protected function parseResponseChoiceMessageToolCallPart(array $toolCallData):
}
$functionArguments = is_string($toolCallData['function']['arguments'])
- ? json_decode($toolCallData['function']['arguments'], true)
+ ? \json_decode($toolCallData['function']['arguments'], true)
: $toolCallData['function']['arguments'];
$functionCall = new FunctionCall(
diff --git a/src/Providers/ProviderRegistry.php b/src/Providers/ProviderRegistry.php
index d5aa6e47..72273f41 100644
--- a/src/Providers/ProviderRegistry.php
+++ b/src/Providers/ProviderRegistry.php
@@ -22,6 +22,14 @@
use WordPress\AiClient\Providers\Models\DTO\ModelMetadata;
use WordPress\AiClient\Providers\Models\DTO\ModelRequirements;
+use function get_class;
+use function is_array;
+use function is_subclass_of;
+use function preg_replace;
+use function sprintf;
+use function str_replace;
+use function strtoupper;
+
/**
* Registry for managing AI providers and their models.
*
@@ -63,7 +71,7 @@ class ProviderRegistry implements WithHttpTransporterInterface
*/
public function registerProvider(string $className): void
{
- if (!class_exists($className)) {
+ if (!\class_exists($className)) {
throw new InvalidArgumentException(
sprintf('Provider class does not exist: %s', $className)
);
@@ -136,7 +144,7 @@ public function registerProvider(string $className): void
*/
public function getRegisteredProviderIds(): array
{
- return array_keys($this->registeredIdsToClassNames);
+ return \array_keys($this->registeredIdsToClassNames);
}
/**
@@ -540,13 +548,13 @@ private function createDefaultProviderRequestAuthentication(
$envVarName = $this->getEnvVarName($providerId, $property);
// Try to get the value from environment variable or constant.
- $envValue = getenv($envVarName);
+ $envValue = \getenv($envVarName);
if ($envValue === false) {
- if (!defined($envVarName)) {
+ if (!\defined($envVarName)) {
continue; // Skip if neither environment variable nor constant is defined.
}
- $envValue = constant($envVarName);
- if (!is_scalar($envValue)) {
+ $envValue = \constant($envVarName);
+ if (!\is_scalar($envValue)) {
continue;
}
}
@@ -554,7 +562,7 @@ private function createDefaultProviderRequestAuthentication(
if (isset($details['type'])) {
switch ($details['type']) {
case 'boolean':
- $authenticationData[$property] = filter_var($envValue, FILTER_VALIDATE_BOOLEAN);
+ $authenticationData[$property] = \filter_var($envValue, \FILTER_VALIDATE_BOOLEAN);
break;
case 'number':
$authenticationData[$property] = (int) $envValue;
@@ -573,7 +581,7 @@ private function createDefaultProviderRequestAuthentication(
if (isset($authenticationSchema['required']) && is_array($authenticationSchema['required'])) {
/** @var list $requiredProperties */
$requiredProperties = $authenticationSchema['required'];
- if (array_diff_key(array_flip($requiredProperties), $authenticationData)) {
+ if (\array_diff_key(\array_flip($requiredProperties), $authenticationData)) {
return null;
}
}
diff --git a/src/Results/DTO/Embedding.php b/src/Results/DTO/Embedding.php
index 076109c6..d2125192 100644
--- a/src/Results/DTO/Embedding.php
+++ b/src/Results/DTO/Embedding.php
@@ -11,6 +11,8 @@
use Traversable;
use WordPress\AiClient\Common\Exception\InvalidArgumentException;
+use function array_is_list;
+
/**
* Represents a single generated embedding vector.
*
@@ -54,7 +56,7 @@ public function __construct(array $values, int $dimensions)
throw new InvalidArgumentException('Embedding values must be integers or floats.');
}
- if (count($values) !== $dimensions) {
+ if (\count($values) !== $dimensions) {
throw new InvalidArgumentException('Embedding vector length must match dimensions.');
}
@@ -74,12 +76,12 @@ public function __construct(array $values, int $dimensions)
*/
private static function isEmbeddingList($values): bool
{
- if (!is_array($values) || !array_is_list($values)) {
+ if (!\is_array($values) || !array_is_list($values)) {
return false;
}
foreach ($values as $value) {
- if (!is_int($value) && !is_float($value)) {
+ if (!\is_int($value) && !\is_float($value)) {
return false;
}
}
diff --git a/src/Results/DTO/EmbeddingResult.php b/src/Results/DTO/EmbeddingResult.php
index d5ebbed1..c0777644 100644
--- a/src/Results/DTO/EmbeddingResult.php
+++ b/src/Results/DTO/EmbeddingResult.php
@@ -270,7 +270,7 @@ public function toArray(): array
{
$data = [
self::KEY_ID => $this->id,
- self::KEY_EMBEDDINGS => array_map(
+ self::KEY_EMBEDDINGS => \array_map(
static fn (Embedding $embedding): array => $embedding->toArray(),
$this->embeddings
),
diff --git a/src/Results/DTO/GenerativeAiResult.php b/src/Results/DTO/GenerativeAiResult.php
index eae903de..cf848cd6 100644
--- a/src/Results/DTO/GenerativeAiResult.php
+++ b/src/Results/DTO/GenerativeAiResult.php
@@ -13,6 +13,11 @@
use WordPress\AiClient\Providers\Models\DTO\ModelMetadata;
use WordPress\AiClient\Results\Contracts\ResultInterface;
+use function array_filter;
+use function array_map;
+use function array_values;
+use function sprintf;
+
/**
* Represents the result of a generative AI operation.
*
@@ -183,7 +188,7 @@ public function getAdditionalData(): array
*/
public function getCandidateCount(): int
{
- return count($this->candidates);
+ return \count($this->candidates);
}
/**
diff --git a/tests/integration/Anthropic/FunctionCallingIntegrationTest.php b/tests/integration/Anthropic/FunctionCallingIntegrationTest.php
index a4f66096..adfb0643 100644
--- a/tests/integration/Anthropic/FunctionCallingIntegrationTest.php
+++ b/tests/integration/Anthropic/FunctionCallingIntegrationTest.php
@@ -14,6 +14,8 @@
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
use WordPress\AiClient\Tools\DTO\FunctionResponse;
+use function stripos;
+
/**
* Integration tests for Anthropic function calling.
*
diff --git a/tests/integration/Google/FunctionCallingIntegrationTest.php b/tests/integration/Google/FunctionCallingIntegrationTest.php
index 9670b5b7..5489f220 100644
--- a/tests/integration/Google/FunctionCallingIntegrationTest.php
+++ b/tests/integration/Google/FunctionCallingIntegrationTest.php
@@ -14,6 +14,8 @@
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
use WordPress\AiClient\Tools\DTO\FunctionResponse;
+use function stripos;
+
/**
* Integration tests for Google function calling.
*
diff --git a/tests/integration/OpenAi/EmbeddingGenerationIntegrationTest.php b/tests/integration/OpenAi/EmbeddingGenerationIntegrationTest.php
index 2970238b..80aa2925 100644
--- a/tests/integration/OpenAi/EmbeddingGenerationIntegrationTest.php
+++ b/tests/integration/OpenAi/EmbeddingGenerationIntegrationTest.php
@@ -10,6 +10,8 @@
use WordPress\AiClient\Results\DTO\EmbeddingResult;
use WordPress\AiClient\Tests\integration\traits\IntegrationTestTrait;
+use function count;
+
/**
* Integration tests for OpenAI embedding generation.
*
diff --git a/tests/integration/OpenAi/FunctionCallingIntegrationTest.php b/tests/integration/OpenAi/FunctionCallingIntegrationTest.php
index 88229e15..4c2f1716 100644
--- a/tests/integration/OpenAi/FunctionCallingIntegrationTest.php
+++ b/tests/integration/OpenAi/FunctionCallingIntegrationTest.php
@@ -14,6 +14,8 @@
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
use WordPress\AiClient\Tools\DTO\FunctionResponse;
+use function stripos;
+
/**
* Integration tests for OpenAI function calling.
*
diff --git a/tests/integration/traits/IntegrationTestTrait.php b/tests/integration/traits/IntegrationTestTrait.php
index 11d122a8..7357b1ac 100644
--- a/tests/integration/traits/IntegrationTestTrait.php
+++ b/tests/integration/traits/IntegrationTestTrait.php
@@ -20,7 +20,7 @@ trait IntegrationTestTrait
protected function requireApiKey(string $envVar): void
{
// Check both $_ENV (populated by symfony/dotenv) and getenv() (shell environment)
- $value = $_ENV[$envVar] ?? getenv($envVar);
+ $value = $_ENV[$envVar] ?? \getenv($envVar);
if ($value === false || $value === '' || $value === null) {
$this->markTestSkipped("Skipping: {$envVar} environment variable is not set.");
}
diff --git a/tests/mocks/MockCache.php b/tests/mocks/MockCache.php
index d6429de4..54a5b651 100644
--- a/tests/mocks/MockCache.php
+++ b/tests/mocks/MockCache.php
@@ -132,7 +132,7 @@ public function deleteMultiple($keys): bool
public function has($key): bool
{
$this->operations[] = ['operation' => 'has', 'key' => $key];
- return array_key_exists($key, $this->cache);
+ return \array_key_exists($key, $this->cache);
}
/**
@@ -153,7 +153,7 @@ public function getOperations(): array
*/
public function getOperationsOfType(string $operation): array
{
- return array_values(array_filter(
+ return \array_values(\array_filter(
$this->operations,
static function (array $op) use ($operation): bool {
return $op['operation'] === $operation;
diff --git a/tests/mocks/MockEventDispatcher.php b/tests/mocks/MockEventDispatcher.php
index f7e5507c..c4822642 100644
--- a/tests/mocks/MockEventDispatcher.php
+++ b/tests/mocks/MockEventDispatcher.php
@@ -34,7 +34,7 @@ public function dispatch(object $event): object
{
$this->dispatchedEvents[] = $event;
- $eventClass = get_class($event);
+ $eventClass = \get_class($event);
if (isset($this->listeners[$eventClass])) {
foreach ($this->listeners[$eventClass] as $listener) {
$listener($event);
@@ -78,7 +78,7 @@ public function getDispatchedEvents(): array
*/
public function getDispatchedEventsOfType(string $eventClass): array
{
- return array_values(array_filter(
+ return \array_values(\array_filter(
$this->dispatchedEvents,
static function (object $event) use ($eventClass): bool {
return $event instanceof $eventClass;
diff --git a/tests/mocks/MockModelMetadataDirectory.php b/tests/mocks/MockModelMetadataDirectory.php
index 9ade638d..af6162da 100644
--- a/tests/mocks/MockModelMetadataDirectory.php
+++ b/tests/mocks/MockModelMetadataDirectory.php
@@ -43,7 +43,7 @@ public function __construct(array $models = [])
*/
public function listModelMetadata(): array
{
- return array_values($this->models);
+ return \array_values($this->models);
}
/**
@@ -61,7 +61,7 @@ public function getModelMetadata(string $modelId): ModelMetadata
{
if (!isset($this->models[$modelId])) {
throw new InvalidArgumentException(
- sprintf('Model not found: %s', $modelId)
+ \sprintf('Model not found: %s', $modelId)
);
}
diff --git a/tests/traits/ArrayTransformationTestTrait.php b/tests/traits/ArrayTransformationTestTrait.php
index 159b573f..16a11525 100644
--- a/tests/traits/ArrayTransformationTestTrait.php
+++ b/tests/traits/ArrayTransformationTestTrait.php
@@ -51,7 +51,7 @@ protected function assertToArrayReturnsArray($object): array
protected function assertArrayRoundTrip($original, callable $assertCallback): void
{
$array = $original->toArray();
- $className = get_class($original);
+ $className = \get_class($original);
$restored = $className::fromArray($array);
$this->assertInstanceOf($className, $restored, 'fromArray() should return instance of ' . $className);
diff --git a/tests/traits/EnumTestTrait.php b/tests/traits/EnumTestTrait.php
index e4bb34c7..536df88f 100644
--- a/tests/traits/EnumTestTrait.php
+++ b/tests/traits/EnumTestTrait.php
@@ -7,6 +7,8 @@
use BadMethodCallException;
use WordPress\AiClient\Common\AbstractEnum;
+use function reset;
+
/**
* Trait for testing enum classes.
*/
@@ -37,7 +39,7 @@ public function testEnumHasExpectedValues(): void
$actualValues = $enumClass::getValues();
// Since getValues() now returns just the values, we need to extract values from expected
- $expectedValuesList = array_values($expectedValues);
+ $expectedValuesList = \array_values($expectedValues);
$this->assertEquals($expectedValuesList, $actualValues);
}
@@ -52,7 +54,7 @@ public function testEnumCasesReturnCorrectInstances(): void
$cases = $enumClass::cases();
- $this->assertCount(count($expectedValues), $cases);
+ $this->assertCount(\count($expectedValues), $cases);
foreach ($cases as $case) {
$this->assertInstanceOf($enumClass, $case);
diff --git a/tests/traits/MockModelCreationTrait.php b/tests/traits/MockModelCreationTrait.php
index 17119f81..9a26db78 100644
--- a/tests/traits/MockModelCreationTrait.php
+++ b/tests/traits/MockModelCreationTrait.php
@@ -103,7 +103,7 @@ protected function createTestEmbeddingResult(?array $embeddings = null): Embeddi
return new EmbeddingResult(
'test-embedding-result-id',
$embeddings,
- count($embeddings[0]),
+ \count($embeddings[0]),
new TokenUsage(10, 0, 10),
$providerMetadata,
$modelMetadata
diff --git a/tests/unit/AiClientTest.php b/tests/unit/AiClientTest.php
index 8eed1337..f9139938 100644
--- a/tests/unit/AiClientTest.php
+++ b/tests/unit/AiClientTest.php
@@ -208,7 +208,7 @@ public function testGenerateEmbeddingsReturnsBatchVectors(): void
$embeddings = AiClient::generateEmbeddings(['First prompt', 'Second prompt'], $mockModel, $registry);
- $this->assertSame($expectedEmbeddings, array_map(
+ $this->assertSame($expectedEmbeddings, \array_map(
static fn ($embedding): array => $embedding->getValues(),
$embeddings
));
diff --git a/tests/unit/Builders/EmbeddingBuilderTest.php b/tests/unit/Builders/EmbeddingBuilderTest.php
index bb40f658..3adeff1a 100644
--- a/tests/unit/Builders/EmbeddingBuilderTest.php
+++ b/tests/unit/Builders/EmbeddingBuilderTest.php
@@ -126,7 +126,7 @@ public function testGenerateEmbeddingsReturnsBatchVectors(): void
$builder = new EmbeddingBuilder($this->registry, ['First input', 'Second input']);
$builder->usingModel($model);
- $this->assertSame($embeddings, array_map(
+ $this->assertSame($embeddings, \array_map(
static fn ($embedding): array => $embedding->getValues(),
$builder->generateEmbeddings()
));
diff --git a/tests/unit/Common/AbstractDataTransferObjectTest.php b/tests/unit/Common/AbstractDataTransferObjectTest.php
index fecb9387..8fe06861 100644
--- a/tests/unit/Common/AbstractDataTransferObjectTest.php
+++ b/tests/unit/Common/AbstractDataTransferObjectTest.php
@@ -11,6 +11,8 @@
use WordPress\AiClient\Common\Contracts\WithArrayTransformationInterface;
use WordPress\AiClient\Common\Contracts\WithJsonSchemaInterface;
+use function json_encode;
+
/**
* Tests for the AbstractDataTransferObject class.
*
@@ -97,7 +99,7 @@ public static function getJsonSchema(): array
// Verify JSON encoding produces correct output
$json = json_encode($result);
$this->assertIsString($json);
- $decoded = json_decode($json, true);
+ $decoded = \json_decode($json, true);
// In JSON, empty object should be {} not []
$this->assertStringContainsString('"emptyObject":{}', $json);
diff --git a/tests/unit/Common/AbstractEnumTest.php b/tests/unit/Common/AbstractEnumTest.php
index ed9944f4..628a4d41 100644
--- a/tests/unit/Common/AbstractEnumTest.php
+++ b/tests/unit/Common/AbstractEnumTest.php
@@ -12,6 +12,8 @@
use WordPress\AiClient\Tests\mocks\Enums\InvalidTypeTestEnum;
use WordPress\AiClient\Tests\mocks\Enums\ValidTestEnum;
+use function array_map;
+
/**
* @covers \WordPress\AiClient\Common\AbstractEnum
*/
diff --git a/tests/unit/Exceptions/ExceptionsTest.php b/tests/unit/Exceptions/ExceptionsTest.php
index 8dd5315c..d915d7e7 100644
--- a/tests/unit/Exceptions/ExceptionsTest.php
+++ b/tests/unit/Exceptions/ExceptionsTest.php
@@ -14,6 +14,8 @@
use WordPress\AiClient\Providers\Http\Exception\NetworkException;
use WordPress\AiClient\Providers\Http\Exception\ServerException;
+use function json_encode;
+
/**
* Tests for AI Client exceptions.
*
diff --git a/tests/unit/Files/DTO/FileTest.php b/tests/unit/Files/DTO/FileTest.php
index 9ac76659..e064fc52 100644
--- a/tests/unit/Files/DTO/FileTest.php
+++ b/tests/unit/Files/DTO/FileTest.php
@@ -11,6 +11,11 @@
use WordPress\AiClient\Files\Enums\FileTypeEnum;
use WordPress\AiClient\Files\ValueObjects\MimeType;
+use function file_put_contents;
+use function sys_get_temp_dir;
+use function tempnam;
+use function unlink;
+
/**
* @covers \WordPress\AiClient\Files\DTO\File
*/
@@ -142,7 +147,7 @@ public function testCreateFromLocalFile(): void
$this->assertEquals(FileTypeEnum::inline(), $file->getFileType());
$this->assertNull($file->getUrl());
- $this->assertEquals(base64_encode('Hello World'), $file->getBase64Data());
+ $this->assertEquals(\base64_encode('Hello World'), $file->getBase64Data());
$this->assertEquals('text/plain', $file->getMimeType());
} finally {
unlink($tempFile);
@@ -183,8 +188,8 @@ public function testNonExistentLocalFileThrowsException(): void
public function testDirectoryThrowsException(): void
{
// Create a directory instead of a file
- $tempDir = sys_get_temp_dir() . '/test_dir_' . uniqid();
- mkdir($tempDir);
+ $tempDir = sys_get_temp_dir() . '/test_dir_' . \uniqid();
+ \mkdir($tempDir);
try {
$this->expectException(InvalidArgumentException::class);
@@ -194,7 +199,7 @@ public function testDirectoryThrowsException(): void
new File($tempDir, 'text/plain');
} finally {
- rmdir($tempDir);
+ \rmdir($tempDir);
}
}
diff --git a/tests/unit/Messages/DTO/MessagePartTest.php b/tests/unit/Messages/DTO/MessagePartTest.php
index de7a4ae0..d1c82789 100644
--- a/tests/unit/Messages/DTO/MessagePartTest.php
+++ b/tests/unit/Messages/DTO/MessagePartTest.php
@@ -118,7 +118,7 @@ public function testCreateWithEmptyString(): void
public function testUnsupportedContentThrowsException($content, string $expectedType): void
{
$this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage(sprintf(
+ $this->expectExceptionMessage(\sprintf(
'Unsupported content type %s. Expected string, File, FunctionCall, or FunctionResponse.',
$expectedType
));
diff --git a/tests/unit/Messages/DTO/MessageTest.php b/tests/unit/Messages/DTO/MessageTest.php
index 3635f83b..a722bb85 100644
--- a/tests/unit/Messages/DTO/MessageTest.php
+++ b/tests/unit/Messages/DTO/MessageTest.php
@@ -351,7 +351,7 @@ public function testArrayRoundTrip(): void
$restored = Message::fromArray($json);
$this->assertEquals($original->getRole()->value, $restored->getRole()->value);
- $this->assertCount(count($original->getParts()), $restored->getParts());
+ $this->assertCount(\count($original->getParts()), $restored->getParts());
$this->assertEquals($original->getParts()[0]->getText(), $restored->getParts()[0]->getText());
$this->assertEquals(
$original->getParts()[1]->getFile()->getUrl(),
diff --git a/tests/unit/Messages/DTO/ModelMessageTest.php b/tests/unit/Messages/DTO/ModelMessageTest.php
index 44345816..b4f2a097 100644
--- a/tests/unit/Messages/DTO/ModelMessageTest.php
+++ b/tests/unit/Messages/DTO/ModelMessageTest.php
@@ -180,7 +180,7 @@ public function testArrayRoundTripWithFunctionCall(): void
]),
function ($original, $restored) {
$this->assertEquals($original->getRole()->value, $restored->getRole()->value);
- $this->assertCount(count($original->getParts()), $restored->getParts());
+ $this->assertCount(\count($original->getParts()), $restored->getParts());
$this->assertEquals(
$original->getParts()[0]->getText(),
$restored->getParts()[0]->getText()
diff --git a/tests/unit/Messages/DTO/UserMessageTest.php b/tests/unit/Messages/DTO/UserMessageTest.php
index c2de91aa..e3fdf2c4 100644
--- a/tests/unit/Messages/DTO/UserMessageTest.php
+++ b/tests/unit/Messages/DTO/UserMessageTest.php
@@ -288,7 +288,7 @@ public function testArrayRoundTrip(): void
]),
function ($original, $restored) {
$this->assertEquals($original->getRole()->value, $restored->getRole()->value);
- $this->assertCount(count($original->getParts()), $restored->getParts());
+ $this->assertCount(\count($original->getParts()), $restored->getParts());
$this->assertEquals(
$original->getParts()[0]->getText(),
$restored->getParts()[0]->getText()
diff --git a/tests/unit/Messages/Util/ModalityCombinationsUtilTest.php b/tests/unit/Messages/Util/ModalityCombinationsUtilTest.php
index 0db9bb1b..2fffffca 100644
--- a/tests/unit/Messages/Util/ModalityCombinationsUtilTest.php
+++ b/tests/unit/Messages/Util/ModalityCombinationsUtilTest.php
@@ -8,6 +8,9 @@
use WordPress\AiClient\Messages\Enums\ModalityEnum;
use WordPress\AiClient\Messages\Util\ModalityCombinationsUtil;
+use function array_map;
+use function count;
+
/**
* @covers \WordPress\AiClient\Messages\Util\ModalityCombinationsUtil
*/
@@ -96,13 +99,13 @@ static function (ModalityEnum $m): string {
},
$combo
);
- sort($values);
- return implode(',', $values);
+ \sort($values);
+ return \implode(',', $values);
},
$combinations
);
- $this->assertCount(count($normalised), array_unique($normalised));
+ $this->assertCount(count($normalised), \array_unique($normalised));
}
/**
@@ -153,10 +156,10 @@ public function testBuildCombinationsEachOptionalAppearsInExactlyHalfTheCombinat
foreach ($optional as $modality) {
$appearances = count(
- array_filter(
+ \array_filter(
$combinations,
static function (array $combo) use ($modality): bool {
- return in_array($modality, $combo, true);
+ return \in_array($modality, $combo, true);
}
)
);
@@ -164,7 +167,7 @@ static function (array $combo) use ($modality): bool {
$this->assertSame(
(int) $expectedAppearances,
$appearances,
- sprintf('Modality "%s" should appear in exactly half the combinations.', $modality->value)
+ \sprintf('Modality "%s" should appear in exactly half the combinations.', $modality->value)
);
}
}
diff --git a/tests/unit/Providers/DTO/ProviderMetadataTest.php b/tests/unit/Providers/DTO/ProviderMetadataTest.php
index 53df16af..b6f9ae0d 100644
--- a/tests/unit/Providers/DTO/ProviderMetadataTest.php
+++ b/tests/unit/Providers/DTO/ProviderMetadataTest.php
@@ -234,8 +234,8 @@ public function testArrayRoundTrip(): void
public function testJsonSerialize(): void
{
$metadata = new ProviderMetadata('json-provider', 'JSON Provider', ProviderTypeEnum::cloud());
- $json = json_encode($metadata);
- $decoded = json_decode($json, true);
+ $json = \json_encode($metadata);
+ $decoded = \json_decode($json, true);
$this->assertIsString($json);
$this->assertIsArray($decoded);
diff --git a/tests/unit/Providers/DTO/ProviderModelsMetadataTest.php b/tests/unit/Providers/DTO/ProviderModelsMetadataTest.php
index e95196fd..80c5a3d6 100644
--- a/tests/unit/Providers/DTO/ProviderModelsMetadataTest.php
+++ b/tests/unit/Providers/DTO/ProviderModelsMetadataTest.php
@@ -16,6 +16,8 @@
use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum;
use WordPress\AiClient\Providers\Models\Enums\OptionEnum;
+use function count;
+
/**
* @covers \WordPress\AiClient\Providers\DTO\ProviderModelsMetadata
*/
@@ -263,8 +265,8 @@ public function testJsonSerialize(): void
[$this->createModelMetadata('json-model', 'JSON Model')]
);
- $json = json_encode($metadata);
- $decoded = json_decode($json, true);
+ $json = \json_encode($metadata);
+ $decoded = \json_decode($json, true);
$this->assertIsString($json);
$this->assertIsArray($decoded);
@@ -346,7 +348,10 @@ public function testNumericArrayKeysPreserved(): void
// Ensure models array has numeric keys starting from 0
$this->assertArrayHasKey(0, $array[ProviderModelsMetadata::KEY_MODELS]);
$this->assertArrayHasKey(1, $array[ProviderModelsMetadata::KEY_MODELS]);
- $this->assertEquals(['models' => array_keys($array[ProviderModelsMetadata::KEY_MODELS])], ['models' => [0, 1]]);
+ $this->assertEquals(
+ ['models' => \array_keys($array[ProviderModelsMetadata::KEY_MODELS])],
+ ['models' => [0, 1]]
+ );
}
/**
diff --git a/tests/unit/Providers/Models/DTO/ModelConfigTest.php b/tests/unit/Providers/Models/DTO/ModelConfigTest.php
index b9819479..de031115 100644
--- a/tests/unit/Providers/Models/DTO/ModelConfigTest.php
+++ b/tests/unit/Providers/Models/DTO/ModelConfigTest.php
@@ -16,6 +16,8 @@
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
use WordPress\AiClient\Tools\DTO\WebSearch;
+use function array_keys;
+
/**
* @covers \WordPress\AiClient\Providers\Models\DTO\ModelConfig
*/
@@ -521,8 +523,8 @@ public function testJsonSerialize(): void
$config->setMaxTokens(1000);
$config->setSystemInstruction('JSON test');
- $json = json_encode($config);
- $decoded = json_decode($json, true);
+ $json = \json_encode($config);
+ $decoded = \json_decode($json, true);
$this->assertIsString($json);
$this->assertIsArray($decoded);
diff --git a/tests/unit/Providers/Models/DTO/ModelMetadataTest.php b/tests/unit/Providers/Models/DTO/ModelMetadataTest.php
index 13192572..c66875f8 100644
--- a/tests/unit/Providers/Models/DTO/ModelMetadataTest.php
+++ b/tests/unit/Providers/Models/DTO/ModelMetadataTest.php
@@ -13,6 +13,9 @@
use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum;
use WordPress\AiClient\Providers\Models\Enums\OptionEnum;
+use function array_keys;
+use function count;
+
/**
* @covers \WordPress\AiClient\Providers\Models\DTO\ModelMetadata
*/
@@ -270,8 +273,8 @@ public function testJsonSerialize(): void
[new SupportedOption(OptionEnum::outputSchema(), [256, 512, 1024])]
);
- $json = json_encode($metadata);
- $decoded = json_decode($json, true);
+ $json = \json_encode($metadata);
+ $decoded = \json_decode($json, true);
$this->assertIsString($json);
$this->assertIsArray($decoded);
@@ -320,7 +323,7 @@ public function testWithAllCapabilities(): void
$this->assertCount(count($allCapabilities), $array[ModelMetadata::KEY_SUPPORTED_CAPABILITIES]);
// Verify all capabilities are preserved
- $expectedValues = array_map(function ($cap) {
+ $expectedValues = \array_map(function ($cap) {
return $cap->value;
}, $allCapabilities);
$this->assertEquals($expectedValues, $array[ModelMetadata::KEY_SUPPORTED_CAPABILITIES]);
diff --git a/tests/unit/Providers/Models/DTO/ModelRequirementsTest.php b/tests/unit/Providers/Models/DTO/ModelRequirementsTest.php
index ddc8f157..3836aad0 100644
--- a/tests/unit/Providers/Models/DTO/ModelRequirementsTest.php
+++ b/tests/unit/Providers/Models/DTO/ModelRequirementsTest.php
@@ -20,6 +20,11 @@
use WordPress\AiClient\Providers\Models\Enums\CapabilityEnum;
use WordPress\AiClient\Providers\Models\Enums\OptionEnum;
+use function array_filter;
+use function array_keys;
+use function array_values;
+use function count;
+
/**
* @covers \WordPress\AiClient\Providers\Models\DTO\ModelRequirements
*/
@@ -234,8 +239,8 @@ public function testJsonSerialize(): void
[new RequiredOption(OptionEnum::outputSchema(), 1536)]
);
- $json = json_encode($requirements);
- $decoded = json_decode($json, true);
+ $json = \json_encode($requirements);
+ $decoded = \json_decode($json, true);
$this->assertIsString($json);
$this->assertIsArray($decoded);
@@ -273,7 +278,7 @@ public function testWithAllCapabilityTypes(): void
$this->assertCount(count($allCapabilities), $array[ModelRequirements::KEY_REQUIRED_CAPABILITIES]);
// Verify all capabilities are preserved with correct values
- $expectedValues = array_map(function ($cap) {
+ $expectedValues = \array_map(function ($cap) {
return $cap->value;
}, $allCapabilities);
$this->assertEquals($expectedValues, $array[ModelRequirements::KEY_REQUIRED_CAPABILITIES]);
diff --git a/tests/unit/Providers/Models/DTO/RequiredOptionTest.php b/tests/unit/Providers/Models/DTO/RequiredOptionTest.php
index b10187af..385784b2 100644
--- a/tests/unit/Providers/Models/DTO/RequiredOptionTest.php
+++ b/tests/unit/Providers/Models/DTO/RequiredOptionTest.php
@@ -160,7 +160,7 @@ public function testGetJsonSchema(): void
$this->assertCount(6, $schema['properties'][RequiredOption::KEY_VALUE]['oneOf']);
// Verify all allowed types
- $types = array_map(function ($item) {
+ $types = \array_map(function ($item) {
return $item['type'];
}, $schema['properties'][RequiredOption::KEY_VALUE]['oneOf']);
$this->assertContains('string', $types);
@@ -326,8 +326,8 @@ public function testJsonSerialize(): void
{
$option = new RequiredOption(OptionEnum::outputSchema(), ['enabled' => true, 'count' => 5]);
- $json = json_encode($option);
- $decoded = json_decode($json, true);
+ $json = \json_encode($option);
+ $decoded = \json_decode($json, true);
$this->assertIsString($json);
$this->assertIsArray($decoded);
diff --git a/tests/unit/Providers/Models/DTO/SupportedOptionTest.php b/tests/unit/Providers/Models/DTO/SupportedOptionTest.php
index 552c4b7b..fcebc02b 100644
--- a/tests/unit/Providers/Models/DTO/SupportedOptionTest.php
+++ b/tests/unit/Providers/Models/DTO/SupportedOptionTest.php
@@ -12,6 +12,11 @@
use WordPress\AiClient\Providers\Models\DTO\SupportedOption;
use WordPress\AiClient\Providers\Models\Enums\OptionEnum;
+use function json_decode;
+use function json_encode;
+use function serialize;
+use function unserialize;
+
/**
* @covers \WordPress\AiClient\Providers\Models\DTO\SupportedOption
*/
@@ -191,7 +196,7 @@ public function testGetJsonSchema(): void
$this->assertArrayHasKey('oneOf', $schema['properties'][SupportedOption::KEY_SUPPORTED_VALUES]['items']);
// Verify all allowed types in items
- $types = array_map(function ($item) {
+ $types = \array_map(function ($item) {
return $item['type'];
}, $schema['properties'][SupportedOption::KEY_SUPPORTED_VALUES]['items']['oneOf']);
$this->assertContains('string', $types);
@@ -378,7 +383,7 @@ public function testArrayValuesProperlyIndexed(): void
$array = $option->toArray();
// Ensure supportedValues array has numeric keys starting from 0
- $this->assertEquals([0, 1, 2], array_keys($array[SupportedOption::KEY_SUPPORTED_VALUES]));
+ $this->assertEquals([0, 1, 2], \array_keys($array[SupportedOption::KEY_SUPPORTED_VALUES]));
}
/**
diff --git a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModelTest.php b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModelTest.php
index b16b68f9..da75df38 100644
--- a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModelTest.php
+++ b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleImageGenerationModelTest.php
@@ -25,6 +25,8 @@
use WordPress\AiClient\Results\Enums\FinishReasonEnum;
use WordPress\AiClient\Tests\mocks\MockOpenAiCompatibleImageGenerationModel;
+use function json_encode;
+
/**
* @covers \WordPress\AiClient\Providers\OpenAiCompatibleImplementation\AbstractOpenAiCompatibleImageGenerationModel
*/
diff --git a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php
index f8e79541..23b4d046 100644
--- a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php
+++ b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleModelMetadataDirectoryTest.php
@@ -13,6 +13,8 @@
use WordPress\AiClient\Providers\Models\DTO\ModelMetadata;
use WordPress\AiClient\Tests\mocks\MockCache;
+use function md5;
+
/**
* @covers \WordPress\AiClient\Providers\OpenAiCompatibleImplementation\AbstractOpenAiCompatibleModelMetadataDirectory
*/
diff --git a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModelTest.php b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModelTest.php
index 6c99c75b..bed5cb42 100644
--- a/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModelTest.php
+++ b/tests/unit/Providers/OpenAiCompatibleImplementation/AbstractOpenAiCompatibleTextGenerationModelTest.php
@@ -27,6 +27,8 @@
use WordPress\AiClient\Tools\DTO\FunctionDeclaration;
use WordPress\AiClient\Tools\DTO\FunctionResponse;
+use function json_encode;
+
/**
* @covers \WordPress\AiClient\Providers\OpenAiCompatibleImplementation\AbstractOpenAiCompatibleTextGenerationModel
*/
@@ -1156,7 +1158,7 @@ public function testParseResponseChoiceToCandidateInvalidFinishReason(): void
$this->expectException(ResponseException::class);
$this->expectExceptionMessage(
- sprintf(
+ \sprintf(
'Unexpected TestProvider API response: Invalid "%s" key: Invalid finish reason "unknown".',
'choices[0].finish_reason'
)
diff --git a/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleModelMetadataDirectory.php b/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleModelMetadataDirectory.php
index 0b647b61..fa499643 100644
--- a/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleModelMetadataDirectory.php
+++ b/tests/unit/Providers/OpenAiCompatibleImplementation/MockOpenAiCompatibleModelMetadataDirectory.php
@@ -101,9 +101,9 @@ protected function parseResponseToModelMetadataList(Response $response): array
{
$data = $response->getData();
$modelsMetadata = [];
- if (isset($data['data']) && is_array($data['data'])) {
+ if (isset($data['data']) && \is_array($data['data'])) {
foreach ($data['data'] as $modelData) {
- if (isset($modelData['id']) && is_string($modelData['id'])) {
+ if (isset($modelData['id']) && \is_string($modelData['id'])) {
if ($this->useRealModelMetadata) {
$modelsMetadata[] = $this->createRealModelMetadata($modelData['id']);
} elseif ($this->modelMetadataStubFactory !== null) {
@@ -126,7 +126,7 @@ private function createRealModelMetadata(string $modelId): ModelMetadata
{
return new ModelMetadata(
$modelId,
- ucfirst($modelId),
+ \ucfirst($modelId),
[CapabilityEnum::textGeneration()],
[]
);
diff --git a/tests/unit/Providers/ProviderRegistryTest.php b/tests/unit/Providers/ProviderRegistryTest.php
index ff8197e6..10fbf956 100644
--- a/tests/unit/Providers/ProviderRegistryTest.php
+++ b/tests/unit/Providers/ProviderRegistryTest.php
@@ -21,6 +21,8 @@
use WordPress\AiClient\Tests\mocks\MockProvider;
use WordPress\AiClient\Tests\mocks\MockProviderAvailability;
+use function putenv;
+
/**
* @covers \WordPress\AiClient\Providers\ProviderRegistry
*/
diff --git a/tests/unit/Results/DTO/CandidateTest.php b/tests/unit/Results/DTO/CandidateTest.php
index 385347ae..91888ff4 100644
--- a/tests/unit/Results/DTO/CandidateTest.php
+++ b/tests/unit/Results/DTO/CandidateTest.php
@@ -360,7 +360,7 @@ public function testArrayRoundTrip(): void
function ($original, $restored) {
$this->assertEquals($original->getFinishReason()->value, $restored->getFinishReason()->value);
$this->assertCount(
- count($original->getMessage()->getParts()),
+ \count($original->getMessage()->getParts()),
$restored->getMessage()->getParts()
);
$this->assertEquals(
diff --git a/tests/unit/Results/DTO/EmbeddingTest.php b/tests/unit/Results/DTO/EmbeddingTest.php
index 00d17aa5..2341d68b 100644
--- a/tests/unit/Results/DTO/EmbeddingTest.php
+++ b/tests/unit/Results/DTO/EmbeddingTest.php
@@ -19,7 +19,7 @@ public function testGettersAndArrayConversion(): void
$this->assertSame([0.1, 1, 0.3], $embedding->getValues());
$this->assertSame(3, $embedding->getDimensions());
- $this->assertSame(3, count($embedding));
+ $this->assertSame(3, \count($embedding));
$this->assertSame([0.1, 1, 0.3], $embedding->toArray());
$this->assertSame([0.1, 1, 0.3], $embedding->jsonSerialize());
}
diff --git a/tests/unit/Results/DTO/GenerativeAiResultTest.php b/tests/unit/Results/DTO/GenerativeAiResultTest.php
index ae1fc7bc..b7f46b20 100644
--- a/tests/unit/Results/DTO/GenerativeAiResultTest.php
+++ b/tests/unit/Results/DTO/GenerativeAiResultTest.php
@@ -882,7 +882,7 @@ public function testArrayRoundTripWithMultipleCandidates(): void
),
function ($original, $restored) {
$this->assertEquals($original->getId(), $restored->getId());
- $this->assertCount(count($original->getCandidates()), $restored->getCandidates());
+ $this->assertCount(\count($original->getCandidates()), $restored->getCandidates());
$this->assertEquals(
$original->getTokenUsage()->getTotalTokens(),
$restored->getTokenUsage()->getTotalTokens()