alibabacloud/tea-utils
Utility toolkit for Alibaba Cloud Tea-based PHP SDKs. Provides helpers for runtime options, parameter validation, JSON/XML parsing, stream and body handling, and common SDK operations. A small dependency package for generated Alibaba Cloud PHP clients, not a standalone service.
alibabacloud/tea-utils is not a standalone utility package you reach for on its own — it is the runtime helper layer that every auto-generated Alibaba Cloud "Tea" SDK depends on. In a Laravel app you will almost always get it transitively:
composer require alibabacloud/dysmsapi-20170525 # pulls in alibabacloud/tea + tea-utils
composer show alibabacloud/tea-utils # confirm version, expect 0.1.x
Look first at vendor/alibabacloud/tea-utils/src/Tea.php. That single class is essentially the whole package: static helpers like merge(), is4xx(), is5xx(), toArray(), assertAsMap(), assertAsString(), getHost(), readAsBytes(), readAsString(), sleep(), and getNonce(). There is no service provider, no config file, no facade — you include it because SDK clients call it internally and occasionally because you need to inspect/reshape the model objects those clients return.
Your first real use case is almost always the same: call an Alibaba Cloud SDK from a Laravel service and turn its typed RuntimeObject response into something your app can log, cache, serialize, and assert on. A minimal loop:
use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
use AlibabaCloud\Tea\Utils\Utils;
use Darabonba\OpenApi\Models\Config;
$config = new Config(['accessKeyId' => config('services.aliyun.key'), 'accessKeySecret' => config('services.aliyun.secret')]);
$config->endpoint = 'dysmsapi.aliyuncs.com';
$client = new Dysmsapi($config);
$response = $client->sendSms($request, new RuntimeOptions([]));
$payload = Utils::toArray($response->body); // plain array: loggable, queueable
Wrap the SDK once, inject everywhere. Bind clients as singletons in a service provider so credentials and endpoint are resolved once, and so tests can swap in fakes:
$this->app->singleton(Dysmsapi::class, fn () => new Dysmsapi(new Config([
'accessKeyId' => config('services.aliyun.key'),
'accessKeySecret' => config('services.aliyun.secret'),
'endpoint' => 'dysmsapi.aliyuncs.com',
])));
Use Utils::merge() for layered request config. It flattens arrays and Tea model objects into a single associative array, which makes it a clean way to combine a base parameter set with per-call overrides before constructing a request object:
$params = Utils::merge(['PhoneNumbers' => $to, 'SignName' => 'App'], $overrides);
Normalize responses before they touch the rest of your app. The generated models are nested RuntimeObjects. Utils::toArray() gives you arrays safe for Log::info(), cache payloads, and queue serialization. Doing this at the service boundary — not deep in controllers — keeps your domain code free of Alibaba types.
Branch retries with is4xx / is5xx. These are the cheapest useful helpers in the package. A 4xx is a bad request (bad phone number, wrong template) — do not retry. A 5xx is transport/provider failure — safe to retry with backoff (though prefer Laravel's $tries/backoff on the queued job over Utils::sleep()):
try {
$client->sendSms($request, new RuntimeOptions([]));
} catch (\AlibabaCloud\Tea\Exception\TeaError $e) {
if (Utils::is5xx($e->getCode())) {
throw $e; // let the queued job retry
}
report($e); // 4xx: surface to the caller, no retry
}
Use the assertAs* family at the parsing edge. When you consume raw webhook/callback payloads or third-party JSON and want the same coercion the SDK uses, Utils::assertAsString(), assertAsMap(), and assertAsNumber() throw on type mismatch instead of silently casting — useful when the shape is contractual. Be aware these throw generic exceptions, so wrap them and translate.
Streaming downloads. For OSS-style responses, Utils::readAsString($stream) / readAsBytes($stream) pair naturally with Laravel's response()->stream() or Storage::put() rather than buffering into memory.
Testing. Because everything is plain PHP with no container coupling, the easiest pattern is to mock the SDK client class and assert your service calls the right request objects. For response fixtures, build arrays and hydrate the SDK's response model rather than hand-rolling Utils::toArray output — it keeps tests honest about the real shape.
Arr, Str, Http, and Cache are better maintained. Reach for Tea only where SDK types force you to.alibabacloud/tea and tea-utils. A composer update on one Ali SDK can resolve an incompatible tea-utils for another. Commit composer.lock, and when bumping an Ali SDK, bump them together and run the SDK's happy-path test immediately.Utils::sleep() takes milliseconds, not seconds. Mixing it up gives you a 1000× backoff. For queued work, prefer Laravel's job backoff() entirely.Utils::merge() deep-flattens and converts objects, so you lose the type information and any null-vs-absent distinction. If downstream code needs strict types, build the request model explicitly instead of merging arrays into it.TeaError/TeaUnableRetryError from the tea base package, not HttpClientException. Map them to your app's domain exceptions in the wrapper layer so controllers never import AlibabaCloud\....Cache::put(). Always Utils::toArray() first — these objects don't serialize cleanly and can carry stream handles.Utils::getHost() and friends are string parsers, not validators. They'll happily return something odd for a malformed endpoint; validate the endpoint from config yourself.Utils::toArray($response) before dd() is the fastest way to see what the SDK actually returned; the raw object dumps are unreadable.alibabacloud/tea and the *CredentialsProvider classes, not here.Http client plus manual signing. That trades correctness guarantees for a dramatically smaller dependency tree — often the right call for a Laravel app that touches exactly one Alibaba service.How can I help you explore Laravel packages today?