比如页面中。需要向用户发邮件和写入用户访问日志等。其实这些并不需要直接表现在页面。因为会影响页面响应速度. 我们可以利用drupal terminate功能将这种功能在terminate event中实现并不需要影响页面输出
terminate功能请看index.php
<?php
/**
* @file
* The PHP page that serves all page requests on a Drupal installation.
*
* All Drupal code is released under the GNU General Public License.
* See COPYRIGHT.txt and LICENSE.txt files in the "core" directory.
*/
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
$autoloader = require_once 'autoload.php';
$kernel = new DrupalKernel('prod', $autoloader);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
在$response->send()了以后其实页面就已经完成了,这里使用的是
fastcgi_finish_request, 这里请看我的另一篇文章。PHP提前响应页面
。下面的$kernel->terminate()这里其实是在后台悄悄完成。drupal提供了event
return [
KernelEvents::TERMINATE => ['onKernelTerminate'],
];
功能实现
先定义一个function用来保存需要在terminate中需要调用的函数和参数
function _terminate_run($callback, $arguments = []) {
$terminate_callbacks = &drupal_static('terminate_callbacks');
if (!isset($terminate_callbacks)) {
$terminate_callbacks = [];
}
$terminate_callbacks[] = [
'callback' => $callback,
'arguments' => $arguments
];
}
接着定义一个服务。用来执行event
services:
mymodule.event_subscriber:
class: Drupal\mymodule\EventSubscriber\AutomatedTaskSubscriber
tags:
- { name: event_subscriber }
定义这个类
<?php
declare(strict_types=1);
namespace Drupal\mymodule\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* @todo Add description for this subscriber.
*/
final class AutomatedTaskSubscriber implements EventSubscriberInterface {
/**
* Kernel response event handler.
*/
public function onKernelTerminate(): void {
// 通过函数获取保存的callback
$terminate_callbacks = drupal_static('terminate_callbacks');
if ($terminate_callbacks) {
foreach ($terminate_callbacks as $callback_infos) {
try {
\Drupal::logger('terminate_callbacks')->notice('terminate callback is running: <pre>' . print_r($callback_infos, true));
call_user_func($callback_infos['callback'], $callback_infos['arguments']);
} catch (\Exception $e) {
\Drupal::logger('terminate_callbacks')->error('terminate callback is error: ' . $e->getMessage());
}
}
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
return [
KernelEvents::TERMINATE => ['onKernelTerminate'],
];
}
}
测试
function write_file_fuc($time) {
file_put_contents('write_file_fuc.txt', $time);
}
/**
* Returns responses for test_code routes.
*/
class TestCodeController extends ControllerBase {
public function writefile($time) {
sleep(10);
file_put_contents('time.txt', $time);
}
/**
* Builds the response.
*/
public function build() {
_terminate_run([$this, 'writefile'], [time()]);
_terminate_run('write_file_fuc', [time()]);
$build['content'] = [
'#type' => 'item',
'#markup' => $this->t('It works!'),
];
return $build;
}
}
这里可以看到。页面响应速度会很快而且不会影响写入一个文件的功能. 就算写入文件需要等10秒也是后端执行
我们通常这里可以用来做一些不影响页面响应但是又要很久的事情。比如发邮件。比如写日志