
本文详解使用 Google Ads PHP 客户端库调用 searchStream() 获取广告系列列表时返回空结果的核心原因——误用经理账号(Manager Account)的 Customer ID,而非子账号(Client Account)ID,并提供可立即运行的修复代码与关键配置说明。
本文详解使用 google ads php 客户端库调用 `searchstream()` 获取广告系列列表时返回空结果的核心原因——误用经理账号(manager account)的 customer id,而非子账号(client account)id,并提供可立即运行的修复代码与关键配置说明。
在 Google Ads API 中,广告系列(Campaign)资源始终归属于具体的客户账号(Client Account),而非上级经理账号(Manager Account)。当你使用经理账号的 Customer ID(如 123456789)发起查询时,API 会严格按该 ID 所代表的账户上下文执行检索——而经理账号本身不直接拥有 Campaign 资源,因此 searchStream() 返回的流为空,导致 foreach ($stream->iterateAllElements() as ...) 循环根本不会执行,var_dump() 也无输出。
✅ 正确做法是:
- 传入目标广告系列实际所属的子账号 Customer ID(例如 1138211281)作为 searchStream() 的第一个参数;
- 同时通过 withLoginCustomerId() 显式指定经理账号 ID(仅用于身份授权与访问权限校验),确保 OAuth2 凭据具备对该子账号的操作权限。
以下是修正后的完整示例(适配 Symfony 控制器):
use Google\Ads\GoogleAds\Lib\V15\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V15\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V15\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\V15\Services\GoogleAdsServiceClient;
use Google\Ads\GoogleAds\V15\Services\SearchGoogleAdsStreamRequest;
use Google\Ads\GoogleAds\V15\Resources\Campaign;
// ... 在你的控制器方法中:
$configPath = $this->getParameter('kernel.project_dir') . '/google_ads_php.ini';
if (!is_file($configPath)) {
return $this->json(['error' => 'Config file not found: ' . $configPath]);
}
$oAuth2Credential = (new OAuth2TokenBuilder())
->fromFile($configPath)
->build();
// ✅ 关键修复:设置 login_customer_id(经理账号ID)用于授权
// 注意:此处填入你的经理账号(MCC)ID,不含连字符,如 "1234567890"
$googleAdsClient = (new GoogleAdsClientBuilder())
->fromFile($configPath)
->withOAuth2Credential($oAuth2Credential)
->withLoginCustomerId('1234567890') // ← 必须设置!否则可能因权限不足静默失败
->build();
$customerId = '1138211281'; // ← 此处必须为实际拥有Campaign的子账号ID
try {
$stream = $this->fetchCampaigns($googleAdsClient, $customerId);
$campaigns = [];
foreach ($stream->iterateAllElements() as $row) {
$campaign = $row->getCampaign();
$campaigns[] = [
'id' => $campaign->getId(),
'name' => $campaign->getName(),
'status' => $campaign->getStatus()->value()
];
}
return $this->json([
'total' => count($campaigns),
'campaigns' => $campaigns
]);
} catch (\Google\Ads\GoogleAds\Util\V15\GoogleAdsException $e) {
return $this->json([
'error' => 'Google Ads API error',
'request_id' => $e->getRequestId(),
'errors' => array_map(fn($err) => [
'code' => $err->getErrorCode()->getErrorCode(),
'message' => $err->getMessage()
], $e->getGoogleAdsFailure()->getErrors())
], 400);
} catch (\Google\ApiCore\ApiException $e) {
return $this->json([
'error' => 'gRPC API exception',
'message' => $e->getMessage()
], 500);
}
// —— 提取为独立方法便于复用 ——
private function fetchCampaigns(GoogleAdsClient $client, string $customerId): \Google\Ads\GoogleAds\Lib\V15\GoogleAdsServerStreamDecorator
{
$serviceClient = $client->getGoogleAdsServiceClient();
$query = 'SELECT campaign.id, campaign.name, campaign.status FROM campaign ORDER BY campaign.id';
return $serviceClient->searchStream($customerId, $query);
}⚠️ 重要注意事项:
立即学习“PHP免费学习笔记(深入)”;
- Customer ID 格式:必须为纯数字(10 位),不可带连字符或空格(如 123-456-7890 → 应传 1234567890);
- 权限验证:确保 OAuth2 凭据已获该子账号的「标准访问」或「管理员访问」权限(可通过 Google Ads 界面 > 工具与设置 > 共享 > 访问权限确认);
- 错误静默风险:若遗漏 withLoginCustomerId(),某些场景下 API 可能返回空流而不抛异常,务必主动校验 $stream->iterateAllElements() 是否有元素;
- 分页与性能:searchStream() 默认单次响应最多 10,000 行,超量数据需结合 pageToken 分页处理(本例未涉及,但生产环境应考虑)。
总结:Google Ads PHP SDK 中“查不到 Campaign”问题,90% 源于 Customer ID 使用错误。牢记口诀:查询用子号,授权靠经理号。正确配置 withLoginCustomerId() 并传入真实子账号 ID,即可稳定获取广告系列列表。











