viezel / amplitude-php-sdk
Amplitude 的 PHP SDK
Requires (Dev)
- php-coveralls/php-coveralls: ^2.4
- phpunit/phpunit: ^9.6
- squizlabs/php_codesniffer: 3.4.*
README
目录
关于项目
这是一个较为轻量级的 PHP API,用于 Amplitude,从 zumba/Amplitude-php 分支而来,并进行修改。
- 使用相同用户和 Amplitude 应用的多个事件 - 当您跟踪可能针对同一用户、同一 Amplitude 应用的多个事件时。此库提供了一个 Singleton 实例,允许在页面加载时初始化 API 密钥和用户信息,该信息用于在该页面加载期间记录的任何事件。
- 跨多个用户和可能的多个 Amplitude 应用程序的事件 - 在您可能需要为大量不同的用户记录多个事件的情况下,可能使用不同的 amplitude 应用程序。
入门
您现在可以使用 sdk 如下所示
// After User is Initialized in your application, set the user info in Amplitude that you want to track (minimally // the user identifier or device identifier, and of course your Amplitude App API key) $amplitude = \Viezel\Amplitude\Amplitude::getInstance(); $amplitude->init('APIKEY', 'johnny@example.com') ->setUserProperties([ 'dob' => '1980-11-04', 'name' => 'Johnny 5' ]) // Only call this once API Key and user ID or device ID is set ->logQueuedEvents(); // -- Meanwhile, in another part of the code... -- // Anywhere else in your application that needs to log an event // This will even work if called before the above code initializes Amplitude! If that is case, it will queue it // and send the event when logQueuedEvents() is called. \Viezel\Amplitude\Amplitude::getInstance() ->queueEvent('EVENT TYPE'); // Can pass in an array for the second parameter to set event properties \Viezel\Amplitude\Amplitude::getInstance() ->queueEvent('SECOND EVENT', ['quantity' => 1, 'price' => 15.32, 'Custom Property' => 'Widgets']); // This is a simple example to get you started, see the rest of the readme for more examples
当您最初设置您的应用程序时,如果您的活动没有在 Amplitude 中显示,您可能需要进行一些故障排除。通常,您看到您的活动首次在您的 Amplitude 应用程序中显示是“它工作”的指标。
如果您从未看到那个第一个事件出现,您可以看到当事件记录时 Amplitude 的响应。这可能有助于找到并解决问题(例如无效的 API 密钥、PHP 环境错误、连接问题等。)
Amplitude 使用 Psr\Logger
记录与 Amplitude HTTP API 的通信。您可以通过设置一个记录器(使用 $amlitude->setLogger()
)来利用此功能,以帮助捕获任何问题。
匿名用户
由于这是一个 PHP SDK,因此有许多跟踪匿名用户的选择。由于这可以在 CLI 模式或作为 cron 作业中运行,因此此 SDK 不为您处理会话。
您的应用程序需要找出一种方法来跟踪跨多个页面加载的用户,可能性很大,您的应用程序已经在 PHP 会话或类似的东西中这样做。
一旦您有了允许匿名用户在页面加载之间跟踪的唯一标识符,将其设置为 deviceId
。对于已登录用户和匿名用户都这样做,这样一旦用户登录,他们的过去事件就会与用户相关联。
// After your application has set up the session (for instance in your bootloader or similar), initialize Amplitude: $amplitude = \Viezel\Amplitude\Amplitude::getInstance(); // Notice we are not setting second parameter here for user ID, we will do that below if it is available $amplitude->init('APIKEY'); // Can use the PHP session ID, or alternatively, any unique string your application uses to track sessions $sessionId = session_id(); // Keep track of whether we have a session or user ID $canLogEvents = false; if (!empty($sessionId)) { $amplitude->setDeviceId($sessionId); $canLogEvents = true; } // Presumes $applicationUserId set prior to this by your application if (!empty($applicationUserId)) { $amplitude->setUserId($applicationUserId); $canLogEvents = true; } if (!empty($userData)) { // If you have other user properties, set them as well... They will be set on the first event sent to Amplitude $amplitude->setUserProperties($userData); } if ($canLogEvents) { // Make sure to send any events that may have gotten queued early $amplitude->logQueuedEvents(); } else { // Do not have a user ID or device ID for this page load, so set `optOut`, to prevent amplitude from trying // to send events (since it won't work without user or device ID) $amplitude->setOptOut(true); } // -- Meanwhile, in another part of the code... -- // Just queue events as normal \Viezel\Amplitude\Amplitude::getInstance()->queueEvent('EVENT_TYPE');
用户属性
设置用户属性主要有一种方式,这会将用户属性与发送到 Amplitude 的下一个事件一起发送
\Viezel\Amplitude\Amplitude::getInstance() ->setUserProperties( [ 'name' => 'Jane', 'dob' => $dob, // ... ] );
您通常会在调用 logQueuedEvents()
之前调用此方法,以确保它与第一个排队的事件(如果有)一起发送。
使用此方法,它只与一个事件一起发送用户信息,因为一旦在 Amplitude 中设置用户属性,它将持久化到所有与用户 ID 或事件 ID 匹配的事件。
请注意,如果在发送 setUserProperties()
之后没有发送事件,则不会将那些属性发送到 Amplitude。
一种方法是使用登录事件,在用户登录时添加用户信息,并通过登录事件发送。这样,你只需发送用户在登录页面加载时的属性。
或者,在初始化Amplitude对象时,为每次页面加载添加用户属性。这是示例中使用的选项。
在事件对象上添加用户属性
另一种设置用户属性的方法是在事件对象本身上设置。你可以通过设置/更改userProperties
,或者在Event
对象上使用setUserProperties()
方法来实现。
通常,在类似下一节中描述的情况中,你会使用这种方法,比如在同一页面加载中发送不同用户的事件的时刻。
$event = new \Viezel\Amplitude\Event(); // Method 1 - set user properties method: $event->setUserProperties( [ 'name' => 'Rambo', // ... ] ); // If you called setUserProperties() a second time, it would overwrite any properties with the same name but leave // others intact // Method 2 - just set the userProperties directly: $event->userProperties = [ 'name' => 'Mary', // ... ]; // This works just like you would expect: it will reset what is already there. // Note that prior to anything being set, $event->userProperties will be null, not an empty array
有关事件对象如何工作的更多信息,请参阅下面的事件部分。
用例:许多用户的事件
在需要发送许多针对不同用户的Amplitude事件的情况下,你实际上可以在事件对象本身上添加用户属性,就像我们在上一节中讨论的那样。事实上,除了API密钥之外,所有内容都可以在事件对象上设置。
例如
// Here, we are not using Singleton as we will only use this connection to send these batch user events, we don't // want any user data from the Singleton instance to accidentally bleed into the first user's event $amplitude = new \Viezel\Amplitude\Amlitude(); // Alternatively, if we wanted to re-use the same Amplitude object with the same key elsewhere in the code, could // have used: // $amplitude = \Viezel\Amplitude\Amplitude::getInstance('NAMED-INSTANCE'); // That will maintain the same Amplitude instance anywhere that requests that specific name. $amplitude->init('APIKEY'); // $userEvents might be an array your application generates with user info and events that need to be sent foreach ($userEvents as $myUserEvent) { $event = $amplitude->event(); // Notice below we are setting user ID and user data on the event itself, not inside Amplitude where it would end // up persisting the user ID between logged events... // The below assumes an array set like so: /* $myUserEvent = [ 'id' => 'user-id', 'user_details' => [], // key/value array of user info 'event_type' => 'EVENT', // event to log 'event_properties' => [], // key/value array of event properties to set ]; */ $event->userId = $myUserEvent['id']; $event->userProperties = $myUserEvent['user_details']; $event->eventType = $myUserEvent['event_type']; $event->set($myUserEvent['event_properties']); // Since we used $amplitude->event() to get event object, it will be the event to be sent when we call this $amplitude->logEvent(); // Above we are using logEvent instead of queueEvent since the code is not "spread out", we can ensure that // amplitude is already initialized and all the requirements (eventType and either userId or deviceId) are set // on the event already }
有关如何使用Event
对象进行操作的更多详细信息,请参阅下一节。
事件
这个库非常灵活,在如何设置要发送到Amplitude的事件方面为你提供了选择。使用最适合你个人偏好和项目需求的方法。
直接发送!
第一种方法是最简单的,即主示例中使用的方法。只需调用queueEvent
或logEvent
,并提供事件类型和事件属性(如果有)。但要知道,根据你使用的方法,你必须调用相应的方法来发送你的事件。
queueEvent
将事件排队,该事件将与通过logQueuedEvents
排队的所有其他事件一起发送。logEvent
立即发送事件。
// Send just event with no event properties: \Viezel\Amplitude\Amplitude::getInstance() ->logEvent('EVENT-NAME'); // Queue event and add a property: \Viezel\Amplitude\Amplitude::getInstance() ->logEvent('EVENT-NAME', ['property1' => 'value1']);
使用事件对象
如果你觉得使用事件对象来设置事件更方便,你可以选择这样做。以下是如何实现的示例:
// Get the next event that will be queued or sent: $event = \Viezel\Amplitude\Amplitude::getInstance()->event(); // Set up the event here, by setting properties... $event->eventType = 'EVENT-NAME'; // Queue or send the event - since we got the event using the event method, it will be the one used on the next // queue or send, no need to pass it back in. \Viezel\Amplitude\Amplitude::getInstance()->queueEvent(); // Will queue current stored event. $eventType or $props are // provided, it will erase the matching props and the event type. // You can also log your stored event directly. \Viezel\Amplitude\Amplitude::getInstance()->logEvent();
设置事件属性
一旦你有那个$event
对象,你就有几种设置事件属性在事件对象上的选项
// First, probably the most common, you can use the magic set methods to just set the property like this: $event->propertyName = 'property value'; // Set using set(), handy for property names that are invalid as PHP variables: $event->set('Property name with Space', 'property value'); // Set can be chained: $event->set('prop1', 'val1') ->set('prop2', 'val2') ->set('prop3', 'val3'); // Pass in array of properties for the first parameter: $event->set( [ 'prop1' => 'val1', 'prop2' => 'val2', ] );
对于你只想快速设置一些属性在下一个将被排队的或发送的事件上,但还未准备好实际发送或排队事件的情况,你可以将属性数组传递给$amplitude->event()
方法。
// Convenience way to quickly add properties to an event, just pass in array of properties to the event method: \Viezel\Viezel\Amplitude::getInstance()->event( [ 'eventProp' => 'Event Value', 'productId' => 'acme-widget-45', 'price' => 15.32, ] ); // The above is equivalent to: $event = \Viezel\Viezel\Amplitude::getInstance()->event(); $event->setProperties( [ 'eventProp' => 'Event Value', 'productId' => 'acme-widget-45', 'price' => 15.32, ] );
取消设置事件属性
如果某个属性已经在事件上设置了,你可以取消设置。
// For non-standard property names, use the unsetProperty method: $event->unsetProperty('My Location'); // Magic unset also works unset($event->productId);
发送或排队事件
一旦你设置了所有的事件属性,你可以通过调用$amplitude->queueEvent()
或$amplitude->logEvent()
来发送或排队事件。
注意:如果你刚刚创建了一个新的Event
对象,在调用queueEvent()
或logEvent()
之前,你必须像这样将事件传递给Amplitude:
$event = new \Viezel\Amplitude\Event(); // Set event properties here // Pass the event into amplitude and queue it \Viezel\Amplitude\Amplitude::getInstance() ->event($event) ->queueEvent();
然而,如果你使用了事件方法来获取事件,就没有必要将其传递回Amplitude。
$event = \Viezel\Amplitude\Amplitude::getInstance()->event(); // Set event properties here // Send that event \Viezel\Amplitude\Amplitude::getInstance()->queueEvent();
换句话说,当直接处理Event
对象时,它必须以某种方式通过Amplitude的event()
方法传递,在尝试调用queueEvent()
或logEvent()
之前。
技巧和窍门
高效使用 Amplitude
如果你需要在代码的不同部分设置事件,你可以选择传递那个事件,但你不必这样做,因为只要你在使用同一实例,Amplitude就会跟踪下一个要发送或排队的下一个事件对象。所以你可以这样做:
$event = \Viezel\Amplitude\Amplitude::getInstance()->event(); $event->eventType = 'Complicated Event'; // -- Meanwhile, in another part of the code... -- // As long as the event has not yet been sent or queued up, you can get it and change it as needed: $event = \Viezel\Amplitude\Amplitude::getInstance()->event(); $event->deviceId = 'DEVICE ID'; // Just remember, once finished setting up the event, call queueEvent() or logEvent() once. \Viezel\Amplitude\Amplitude::getInstance()->queueEvent();
不要忘记 eventType
在使用事件对象时,请记住,在将事件排队或记录之前,必须以某种方式设置 eventType
。
// Either set it this way: $event->eventType = 'EVENT'; // OR set it when logging/queuing the event: \Viezel\Amplitude\Amplitude::getInstance() ->queueEvent('EVENT');
请注意,在调用 queueEvent()
或 logEvent()
时设置它将覆盖事件对象中已设置的 eventType
,但任何其他在事件上设置的属性将保持不变。
自定义事件工厂
假设你想创建一个工厂,该工厂正在生成要发送的事件,也许每个事件都已经设置了它自己的用户 ID... 你可以这样做
$amplitude = \Viezel\Amplitude\Amplitude::getInstance() ->init('APIKEY'); foreach ($eventFactory->getEvents() as $event) { $amplitude->event($event) ->queueEvent(); } // And then send all queued events. $amplitude->logQueuedEvents();
queueEvent() 与 logEvent()
区别是什么?
- 两者都
- 需要设置非空的
eventType
。 logEvent()
:- 需要设置 API Key,如果没有设置将抛出异常。
- 需要设置
userId
或deviceId
,如果没有在 amplitude 实例或事件本身上设置,将抛出异常。 - 始终在调用时发送事件,假设满足要求。
queueEvent()
:- 不需要首先设置 API key (重要)。
- 不需要首先设置
userId
或deviceId
(重要)。 - 无论如何,它都会将事件添加到内部队列中。这个队列不会跨页面加载持久化,如果在页面加载期间队列中还有事件,如果没有在这次页面加载中发送,它们将会丢失。
- 如果你使用这个,在初始化 Amplitude(设置 API key 和 amplitude 中的
userId
或deviceId
)之后,请务必调用$amplitude->logQueuedEvents()
以发送队列中的任何事件。如果队列为空,无需担心,什么都不会发生。
你为什么要在 queueEvent()
而不是 logEvent()
中使用 logEvent()
?这种用法是在发送多个用户的事件时,你初始化数据然后立即发送。在这种情况下使用 logEvent()
,你可以立即捕获到如果没有立即初始化(它将抛出逻辑异常),而不是“悄悄”地启动一个你可能永远不会处理的队列(如果你没有预期会有一个队列)。
简而言之: 如果你知道你将在调用事件之前始终初始化 amplitude,你可以直接使用 logEvent()
。否则,使用 queueEvent()
并确保在 Amplitude 初始化和用户数据设置后调用 $amplitude->logQueuedEvents()
。
故障排除
独立脚本
以下是一个独立脚本,旨在复制到应用程序文档根目录的 PHP 文件中。只需更改 APIKEY
,如果需要,调整需要 composer 的 autoload.php
文件的行。然后从浏览器中访问脚本的 URL 以查看记录的消息。
<?php // Stand-alone Amplitude troubleshooting script - just change APIKEY in next line $apikey = 'APIKEY'; // Composer Autoloader - If new to composer, see https://getcomposer.org.cn require __DIR__ . '/vendor/autoload.php'; // Make sure if there is some error, we will see it ini_set('display_errors', true); error_reporting(E_ALL); // Quick logger to display log messages - NOT for production use, this displays log message to the browser class ChattyLogger extends \Psr\Log\AbstractLogger { public function log($level, $message, array $context = []) { echo "<p><strong>".ucfirst($level).":</strong> $message<br>"; if (!empty($context)) { echo '<strong>Context:</strong><br><span class="code">'.print_r($context,true).'</span>'; } echo '</p>'; } } $chatty = new ChattyLogger(); // Test logging an event ?> <style> .code { display: inline-block; border: 1px solid #a7a7a7; padding: 15px; margin: 0 5px; background-color: #eaeaea; white-space: pre; } p { padding-bottom: 5px; border-bottom: thin dashed gray; } </style> <h1>Testing Amplitude Log Event Response</h1> <h2>API Key: '<?= $apikey ?>'</h2> <?php $amplitude = new \Viezel\Amplitude\Amplitude(); // Add the chatty logger so we can see log messages $amplitude->setLogger($chatty); // Initialize Amplitude with the API key and a dummy test user ID $amplitude->init($apikey, 'TEST-USER-ID'); $chatty->info('Calling $amplitude->logEvent(\'TEST EVENT\')...'); // Log a test event $amplitude->logEvent('TEST EVENT'); $chatty->info('Done logging event');
故障排除技巧
- Amplitude 库将抛出
\DomainException
。例如- 如果你尝试排队一个没有 event_type 的事件,库将抛出
\DomainException
- 如果你尝试排队一个没有 event_type 的事件,库将抛出
- 确保启用 PHP 错误日志记录(或启用显示错误),这样你就可以看到可能指向问题的任何 PHP 错误。
- 使用 amplitude 中的
setLogger(...)
方法使用你的应用程序日志或上述独立测试脚本中自己的自定义日志记录器。只要它实现了Psr\Log\LoggerInterface
。- 如果没有生成日志:它没有在设置应用程序日志记录器后的点尝试发送事件,或者事件使用没有设置日志记录器的不同实例记录。
- 如果你看到记录了
Curl 错误:
,那么在尝试发送请求时出了问题,错误消息和上下文应该有助于指向问题。 - 如果没有 curl 错误,它将记录一条以
Amplitude HTTP API 响应:
开头的信息。成功
且httpCode = 200
:Amplitude 已收到请求,事件应该已被记录。如果您在 Amplitude 中看不到它,请几分钟后再次检查,有时 Amplitude 可能会稍微滞后。- 其他问题:事件未成功记录,请参考消息和上下文以帮助调试问题。