Drupal8模块开发之区块和表单教程

 更新时间:2016年11月25日 16:19  点击:2487
前页我们讲了 Drupal8模块开发之路由、控制器和菜单链接教程 ,现在我们将学习进一步开发Drupal8模块,区块和表单。

上一教程:Drupal8模块开发之路由、控制器和菜单链接教程

在本教程中,我们将学习进一步的开发,我们可以在这个库 (link is external)里找到我们需要的沙盒模块代码示例,里面两个重要的新功能:区块和表单。

为此,我们将创建一个自定义区块来返回一些可配置的文本,在那之后,我们将创建 一个简单的表单来打印输出用户提交到的数据到屏幕上。

 不知道怎么下载这个库的同学看这里:

2014-07-22_074331.jpg

2014-07-22_074244.jpg

Drupal8 区块

在Drupal8里,有一个很酷的新变化时,以往的Block(区块) API 已经转换成了插件的形式(一个全新的概念),这意味着区块将是可被重复使用的功能块(在引擎下),

你现在可以在后台UI界面创建一个Block区块,并在整个网站的任何地方重用它,你现在不会再局限于只能使用一次这个区块。

让我们先创建一个简单的区块来打印"Hello World"到屏幕上! 一般情况下,我们首先需要在模块根文件夹下的src/Plugin/Block目录下创建一个class类

文件DemoBlock.php,我们这里暂且把这个新的区块命名为"DemoBlock", 所以你最终在这个文件中,看到的代码会是像这样:

 

 代码如下 复制代码
<?php
 
namespace DrupaldemoPluginBlock;

use DrupalblockBlockBase;
use DrupalCoreSessionAccountInterface;
 
/**
 * Provides a 'Demo' block.
 *
 * @Block(
 *   id = "demo_block",
 *   admin_label = @Translation("Demo block"),
 * )
 */
 
class DemoBlock extends BlockBase {
  
  /**
   * {@inheritdoc}
   */
  public function build() {   
    return array(
      '#markup' => $this->t('Hello World!'),
    );
  }
  
  /**
   * {@inheritdoc}
   */
  public function access(AccountInterface $account) {
    return $account->hasPermission('access content');
  } 
  
}




像所有其他的class类文件一样,我们要先在开始时先声明类的命名空间。然后,我们使用BlockBase类以便于我们等下可以继承和扩展它,以及也需要使用AccountInterface类以便于让我们可以获取当前登录的用户。然后接下来的一些代码你肯定没有在Drupal 7见过,这就是:annotations注释。

Annotations注释是一个PHP发现工具,使用这些注释,我们可以让Drupal知道我们想注册一个新的区块(@ Block),我们设定了Id号:demo_block 和admin_label :Demo block(这些注视将会通过注视翻译系统被drupal识别)。

 接下来,我们在DemoBlock类里扩展下BlockBase类,我们将实现两个方法(都是最常见的),build()方法是最重的,因为它返回一个可打印的区块信息数组,access()方法控制查看此区块的访问权限,这里传递给它的参数是AccountInterface类的一个实例,在这里,实际传递的就是当前用户信息参数。

 另外一个有趣的事情需要注意的是,我们不再像以前一样使用全局t()函数直接翻译文本了,但是我们会继承使用父类的t()方法,所以你看到的是$this->t().

 就是这样,你现在可以清空缓存,然后进入区块的配置页,最酷的是你现在已经成功创建了一个区块,并且你可以把这个区块放在任何网站里你设定的regions区域。

Drupal 8 区块配置

现在我们已经知道了如何创建一个新的区块,让我们进一步学习下如何用API为它添加配置表单,我们将让你可以编辑此区块,给你一个文本输入框,让你可以输入一个名字,然

后前台就会显示"Hello 名字"来替换 "Hello World".

首先,我们需要定义一个文本框,所以在我们的DemoBlock类里,我们可以添加一个新的方法叫做blockForm():

 代码如下 复制代码
/**
 * {@inheritdoc}
 */
public function blockForm($form, &$form_state) {
  
  $form = parent::blockForm($form, $form_state);
  
  $config = $this->getConfiguration();
 
  $form['demo_block_settings'] = array(
    '#type' => 'textfield',
    '#title' => $this->t('Who'),
    '#description' => $this->t('Who do you want to say hello to?'),
    '#default_value' => isset($config['demo_block_settings']) ? $config['demo_block_settings'] : '',
  );
  
  return $form;
}


这个表单API应该看起来很熟悉,似乎和以往的drupal 7里的差不多,然而,细看之下,你会发现有一些新的东西在里面,首先,我们从父类里获取$form数组(所以我们是在已存在

的表单基础上新增创建我们的字段),标准的面向对像,然后,我们通过BlockBase类定义的getConfiguration()方法来获取配置信息,并且我们把demo_block_settings的值作为了

#default_value的默认值.

接下来,到了我们要对我们传递的字段值进行提交处理并保存进区块配置里的时候了:

 代码如下 复制代码

/**
* {@inheritdoc}
*/
public function blockSubmit($form, &$form_state) {
 
 $this->setConfigurationValue('demo_block_settings', $form_state['values']['demo_block_settings']);
 
}



这个方法也存在于DemoBlock类里,它被用于保存demo_block_settings的值(请注意保持键名的一致性)

最后我们需要调整我们的build()方法,让它在打印Hello时包含name名字:

 代码如下 复制代码


/**
 * {@inheritdoc}
 */
public function build() {
  
  $config = $this->getConfiguration();
  
  if (isset($config['demo_block_settings']) && !empty($config['demo_block_settings'])) {
    $name = $config['demo_block_settings'];
  }
  else {
    $name = $this->t('to no one');
  }
  
  return array(
    '#markup' => $this->t('Hello @name!', array('@name' => $name)),
  ); 
}



现在,这应该看起来相当容易,我们获取区块的配置信息,如果我们的字段值存在,我们就把它打印出来,如果不存在,就打印"to no one", 你现在可以清空缓存后,编辑区块,填写一个值,然后保存,然后你就能在前台看到" Hello + 名字值"了。

 
Drupal 8 表单

最后,我们将在本教程中,探讨如何创建一个简单的表单,由于空间的限制,我不会覆盖它的配置管理(通过表单提交存储值),相反,我将举例说明一个简单的表单设定,然后让提交的值简单的打印在屏幕上,以演示它可以正常工作。

在Drupal 8 里,表单定义函数都在一个class类里被组织在一起,所以让我们定义一个简单的DemoForm类,在src/Form/DemoForm.php中:

 代码如下 复制代码

<?php
 
/**
 * @file
 * Contains DrupaldemoFormDemoForm.
 */
 
namespace DrupaldemoForm;
 
use DrupalCoreFormFormBase;
 
class DemoForm extends FormBase {
  
  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'demo_form';
  }
  
  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, array &$form_state) {
    
    $form['email'] = array(
      '#type' => 'email',
      '#title' => $this->t('Your .com email address.')
    );
    $form['show'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    );
    
    return $form;
  }
  
  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, array &$form_state) {
    
    if (strpos($form_state['values']['email'], '.com') === FALSE ) {
      $this->setFormError('email', $form_state, $this->t('This is not a .com email address.'));
    }
  }
  
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, array &$form_state) {
    
    drupal_set_message($this->t('Your email address is @email', array('@email' => $form_state['values']['email'])));
  }
  
}


除了OOP思想的改变,一切应该看起来像以前的drupal 7 一样熟悉。Form API 仍然基本没有什么变化(除了一些新的表单元素的加入和相关class类的封装),所以会发生什么?

首先,我们使用了命名空间的类和核心的FormBase类,所以接下来我们就可以在我们自己的DemoForm类里扩展它,然后我们实现了4个方法,其中3个应该是很熟悉的。 getFormid()方法是新增的并且是必须要有的,这个方法用于简单的返回form的机器名称,buildForm()方法也是必须要有的,它用于构建一个表单,怎么用?其实就和你之前在drupal 7中的构建方法差不多,validateForm()方法是可选的,它像drupal 7里一样,用于验证表单提交数据,最后,submitForm()方法用于处理提交的表单数据,一切是不是很合乎逻辑组织。

所以,我们想用这个表单实现什么?我们有一个email邮件字段(Drupal 8的新表单元素),我们希望用户填写它,默认情况下,Drupal会检查是否输入了一个正确的邮箱格式的值,但在我们的验证函数里我们会确保它是一个合法的带.com后缀的邮箱地址,如果不是,我们会在字段上设置了一个错误提示,最后提交处理,然后打印一个提示消息在网页上。

为了使用这个表单,我们需要做最后一件事,就是提供为这个表单提供一个路由,所以请编辑demo.routing.yml文件,并增加以下代码:

 代码如下 复制代码

demo.form:
  path: '/demo/form'
  defaults:
    _form: 'DrupaldemoFormDemoForm'
    _title: 'Demo Form'
  requirements:
    _permission: 'access content'


这应该看起来很熟悉,因为我们之前有篇文章介绍过怎么路由一个简单页面,唯一最大的区别是, 在 defaults下面,我们用_form替代了之前的_content,并为_form指定了一个表单类,

这个类就是刚刚我们创建的。

清空缓存后就可以输入地址导航到demo/form,然后就可以看到这个表单并测试它。

如果你熟悉以前drupal 7中的drupal_get_form,也知道怎样加载一个表单的方式,因此,你就可以使用drupal 8中的全局Drupal类 (link is external),比如formBuilder()方法来获取一个表单,像这样

 代码如下 复制代码
$form = Drupal::formBuilder()->getForm('DrupaldemoFormDemoForm');



然后你就可以返回$form 并渲染输出了。

 
结论


在这篇文章中,我们继续探索了Drupal 8模块开发的两个新的话题:区块和表单。我们已经看到了如何创建我们自己的区块(然后你就可以在区块管理界面创建新区块)。我们还学会了如何添加和存储一个自定义的配置值(这个值你可以在稍后使用它)。在表单的话题中,我们看到了一个简单的FormBase类的实现,我们用来把用户提交的数据打印到屏幕上。

 

网站为了提高性能,一般会采用缓存。Drupal中可以实现游客缓存,如果装上Authcache模块可以加速用户登录响应,对不同的role进行动态加载缓存。以下是教程详细过程。

相关文章:Drupal模块讲解-Authcache缓存原理详解教程

本文讲一下如果通过修改authcache的核心代码,来实现缓存页面的个性化内容。

Drupal的模块<a href=高级应用之Authcache-动态加载内容教程" />


通用的缓存,或多或少都是要进行个性化处理的,比如用户名显示、动态加载用户资料、用户好友等等。

一般情况下,这种局部个性化,都是通过两种手段实现:一个是SSI,另一个是CSI。

Authcache本身可以实现局部personalization, 模块叫p13n。

Authcache的ajax模块属于CSI,ESI模块应该是属于SSI,但是由于ESI模块需要搭建varnish服务器,配置VCL,加上服务器的设置问题,会导致ESI容易出错,并且本身ESI传递cookie也会有些问题,因此ESI实际上实现起来相当复杂。

所以,如果我们要使用服务器端的personalization,通过PHP修改根据某些条件修改某些内容的话,需要hack一些authcache的代码。
1. autcache.module文件

找到下面一句,Line 188
// Invoke cache backends and serve page.
修改成如下:

 代码如下 复制代码
 // Invoke cache backends and serve page.
  if (authcache_page_is_cacheable()) {
    $cache = authcache_backend_cache_save();
    authcache_serve_page_from_cache($cache, authcache_key());
  }
  else {
    ////process html result
    global $conf;
    $conf['page_compression'] = FALSE;
 
    $cache = new stdClass();
 
    ////process html result
    $cache->data['body'] = ob_get_contents();
    ob_clean();
 
    foreach (variable_get('authcache_page_process', array()) as $include) {
      require_once DRUPAL_ROOT . '/' . $include;
    }
    foreach (variable_get('authcache_page_process_interface', array()) as $process) {
      require_once DRUPAL_ROOT . '/' . $include;
      if (is_callable($process)) {
        $process($cache);
      }
    }
    echo $cache->data['body'];
  }
  exit;
}


其中,主要是加了else后面的处理代码。
2. authcache.cache.inc文件

从85行开始,到函数结尾,修改成如下格式。

 

 代码如下 复制代码
  $return_compressed = FALSE; ///NEW //Don't send compressed content
 
  if ($page_compression) {
    header('Vary: Accept-Encoding', FALSE);
    // If page_compression is enabled, the cache contains gzipped data.
    if ($return_compressed) {
      // $cache->data['body'] is already gzip'ed, so make sure
      // zlib.output_compression does not compress it once more.
      ini_set('zlib.output_compression', '0');
      header('Content-Encoding: gzip');
    }
    else {
      // The client does not support compression, so unzip the data in the
      // cache. Strip the gzip header and run uncompress.
      $cache->data['body'] = gzinflate(substr(substr($cache->data['body'], 10), 0, -8));
    }
  }
 
  ///NEW
  foreach (variable_get('authcache_page_process', array()) as $include) {
    require_once DRUPAL_ROOT . '/' . $include;
  }
  foreach (variable_get('authcache_page_process_interface', array()) as $process) {
    if (is_callable($process)) {
      $process($cache);
    }
  }



注意,有两个地方,///NEW 标注,表示新加的内容,中间有一段是原有的code。

改完之后,我们就完工了。
如何使用呢?

新建一个文件,比如在custom模块下面,叫custom_authcache.inc,黏贴如下代码:

 代码如下 复制代码
<?php
/**
Add the following lines to settings.php
 
$conf['authcache_page_process'][] = 'sites/all/modules/custom/custom/custom_authcache.inc';
$conf['authcache_page_process_interface'][] = 'custom_authcache_common_process';
 
If you want to add more process interface, add your function name as an item in this array, $conf['authcache_page_process_interface'].
If you want to include file, please add file name to this array, $conf['authcache_page_process']
 
Core Changes:
modules/authcache/authcache.cache.inc
modules/authcache/authcache.module
**/
 
/*
* Process authcache content to replace content
*/
function custom_authcache_common_process(&$cache) {
  $cache->data['body'] = str_ireplace('<span id="replace_placeholder_1"/>', _get_real_data(), $cache->data['body']);
}


看上面的注释,复制两行代码到settings.php文件。
具体的说明注释已经很详细了,相信应该没问题。

这样,这个custom_authcache_common_process函数就可以动态替换HTML里面的内容了,达到了个性化页面的目的。

随着 php5 面向对象的完善,现在很多php主流框架都往面向对象发展。Drupal8为了适应新php主题框架的需要,也将用面向对象的方式取代面向过程,在Proudly Found Elsewhere的倡议下,Dupal8包含了很多看起来不像是为了drupal开发的的代码。

其中最大的变化是引入了Symfony框架,这对开发人员来说,会产生两个重大影响

首先,这可能将会大大增加Drupal开发者的数量,比如那些曾经自认为是大师,不屑于面向过程开发的传统"高端程序猿",现在Drupal8,也是面向对像了,也用了新框架,他们已经没有理由拒绝加入drupal开发者的行列

第二,新的框架内核变化,会给现在那些没有多少PHP现代框架开发经验的人许多恐惧,他们会担心自己不能适应这种开发方式的巨大转变,但是没关系,我们都需要重新学习,学习Symfony框架,还有充满希望的Drupal8, 像其他PHP框架一样,它们都是很容易扩展的,我们要给自己信心。

在目前,Drupal 8 还在其发布周期中,目前最新的版本是alpha12,我们会基于这个版本,来展示一些Drupal 7开发者会先遇到的一些基本变化,我们应该先熟悉这些基本变化。

我怎样创建一个模块?

我们第一件事是要确定必须的文件和文件夹结构来告诉Drupal8识别我们的新模块。在Drupal 7 里,我们必须创建至少2个文件(.info 和 .module文件),但是在Drupal 8里,.info文件替换成了.info.yml,文件里的内容数据信息相同,但格式略有差异。

另一个主要变化是,自定义模块和第三方贡献模块文件夹的存放位置现在被放到了根目录下的modules/,这是因为所有核心的代码已经被移动到了它单独的文件夹core/,当然,在根目录下的modules文件夹内,我们依然鼓励你像以往的Drupal 7 一样,可以创建 custom 和contrib 子文件夹来分别存放你的自定义模块和官网下载的第三方模块。

让我们继续,我们现在先来学习创建一个叫demo(非常简单)的模块,并把它放到modules/custom/文件夹下,正如我之前所提到的,我们需要在这个新创建的demo/文件夹里,创建一个 demo.info.yml 文件,并在文件里输入以下代码:

 代码如下 复制代码
name: Drupal 8 Demo module
description: 'Demo module for Drupal 8 alpha12'
type: module
core: 8.x



这些大部分你应该看着很熟悉吧(name, description and core), type 字段也是现在必须有的一项,它的值可以是module,theme,theme_engine分别定义此文件类型是模块,还是主题或者模板引擎,另外要注意的一件重要的细节是,注意yml文件里的空格,正确缩进可以像数组一样组织数据。

你可以查看此文档 (https://www.drupal.org/node/2000204)说里其他可用的key|value , 然后打开一个模块文件夹下的.info.yml文件,尝试改变key|value,这里是官方的变更说明 (https://www.drupal.org/node/1935708)

现在,只要有这一个文件就足够了,你可以进入导航菜单下的Extend(扩展)页,找到Demo模块,并启用它。

正如我之前提到的,现在我不需要再创建一个.module的文件,drupal 8就已经可以识别此模块了,因为在drupal 8里,.module文件已经不再是必须存在的文件。因为现在大部分的业务逻辑代码都转移到了service类,控制器和插件里,我们稍后会看到这一点。

什么是路由?调用hook_menu()会发生什么?它的回调怎么工作?


在drupal 7里,hook_menu()可能是最能实现这些功能需求的钩子,因为它就是被用于设定路径并且把这些路径和回调函数连接起来,它也用来创建菜单链接和其他一些东西

在Drupal 8里,我们不再需要hook_menu()了,因为我们会大量使用Symfony2的组件来处理路由,这涉及定义一个路由配置和在控制器里处理一个回调(Controller类的方法), 让我们来实际看下它是如何工作的,我们来创建一个简单的页面来输出那句程序界的永恒经典:Hello world!

首先,我们需要为我们的模块创建一个路由文件:demo.routing.yml ,这个文件也是放在demo模块根目录下,在这个文件里,我们可以有如下(简单)路由设定:

 代码如下 复制代码

demo.demo:
  path: '/demo'
  defaults:
    _content: 'DrupaldemoControllerDemoController::demo'
    _title: 'Demo'
  requirements:
    _permission: 'access content'




第一行代码是一个新路由的开始,这个路由的名字叫做demo(原作者真蛋疼,你就不能取一个不一样的路由名嘛,非要和模块名一样,你让我的小伙伴误会了怎么办?),第一个是demo是模块名,第二个demo是路由名.

第二行path, 我们指定了这个路由的注册路径。

第三行defaults默认设置,我们设定了两件事:默认的页面标题(_title)和引用一个DemoController类的一个方法(_content)

第四行requirements要求,我们指定了用户需要有什么权限才能查看该页面。

你可以查此文档 (https://www.drupal.org/node/2092643)知道你还可以在这个路由文件里设定哪些选项。

现在,让我们来创建第一个叫做DemoController的控制器,并且它包含了一个方法叫做:demo(),用于当用户访问该页面时调用此方法。

在模块目录里,创建一个src的文件夹和一个Controller的文件夹,这就是我们存放controller类的地方,好了,进入Controller文件夹,创建文件:DemoController.php。

该控制器的位置,正如我们将看到的一样,把其他类放入src文件夹里是采用PSR-4标准的一部分,在之前,我们有一个更深层更大的文件夹结构(PSR-0标准),但现在有一个过渡阶段,这两种标准的文件夹结构路径都会起作用,所以你如果看到代码类仍然被放在lib/文件夹下,不用觉得奇怪,那是PSR-0标准。

在DemoController.php文件里,我们可以声明我们的类了:

 代码如下 复制代码

<?php
/**
 * @file
 * Contains DrupaldemoControllerDemoController.
 */

namespace DrupaldemoController;

/**
 * DemoController.
 */
class DemoController {
  /**
   * Generates an example page.
   */
  public function demo() {
    return array(
      '#markup' => t('Hello World!'),
    );
  }     
}


这是我们为了在一个页面上显示"Hello World!"的一个结构最简单的实例,在顶部,我们指定了类的命名空间,在下面,我们声明了我们的类

在DemoController类里,我们只需要demo()方法,用来返回一个像以往的drupal 7里一样的渲染数组,没有大量的东西,现在我们要做的就是清空缓存,并在浏览器里输入地址:http://example.com/demo ,然后我们就应该可以看到一个输出有Hello World!的页面!

怎么创建菜单链接?

在Drupal 7里,为了让菜单链接显示在网站上,我们可以在实施hook_menu()时,添加已经注册过的路径,但在Drupal8里,这个不再需要用hook来处理,我们可以像配置一样使用一个yml文件来声明菜单链接

让我们来看看,该怎样创建一个菜单链接来显示在Structure(结构)管理菜单下,首先,我们在我们的模块根目录下创建一个demo.menu_links.yml 文件,在这个文件中,我们将设定菜单链接和在现有网站菜单上的位置,为了实现我们所要做的,我们需要在文件里输入以下代码:

 代码如下 复制代码

demo.demo:
title: Demo Link
description: 'This is a demo link'
parent: system.admin_structure
route_name: demo.demo



这又是一个基于缩进的yml结构文件,

第一行我们定义了模块的菜单链接的机器名(就像之前定义路由一样),接下来,我们设定了链接的标题,描述,父菜单路径(作为子菜单放在该父菜单下),以及该菜单关联的路由名。

父菜单选项的值是父菜单路径(通它的所属模块附加),你想找个这个父菜单链接,你需要查找一些类似的*.menu_links.yml文件,因为这里的值是system.admin_structure,所以我就可以知道,它肯定是由核心的System模块设定的,所以你就可以判断这个父菜单链接存在于system.menu_links.yml文件里。

route_name是我们想要为这个菜单关联的路由名(这们之前创建的),当你清空缓存后,然后输入浏览器地址:http://example.com/admin/structure你应该可以看到一个新的菜单标题和描述,并且此链接是链接到demo/path的,怎么样,很不错吧?
结论

在这篇文章中,我们开始讨论Drupal 8 的模块开发,在这个阶段(alpha12发布),正是开始学习怎样使用新的API接口来开发贡献模块,为此,我会大家一起退出传统框架的思维,用全新的思维一起探索学习Drupal 8的变化。

首先,我们了解了一些基础知识,如何启动一个Drupal8模块(文件和文件夹结构等),所有这些与Drupal 7的不同之处,我们还看到了如何设定路由和一个控制器类的方法来调用一个路由地址,最后,我们已经看到了如何创建一个使用我们所定义路由的菜单链接。

在接下来的教程中,我们将继续构建完善这个模块,并期待发现在Drupal8中其他一些很酷的东西,我们将看到我们如何创建区块和如何配合使用表单和配置管理系统,下期见。

swoole重新定义PHP语言的高性能网络通信框架,提供了PHP语言的异步多线程服务了,下面我们为了证实它就来做一个例子测试一下吧。

Swoole 提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询.
swoole以前听过, 拿来做游戏服务器简直是神器…今天稍微的感受了一下,  在 ubuntu 下搭建了环境, 测试了一下

测试代码:

 代码如下 复制代码

<?php
class page extends Controller
{
    function index()
    {
        $data = createModel('UserInfo')->get(12)->get();
        $this->swoole->tpl->assign('data',$data);
        $html = $this->swoole->tpl->fetch('test.html');
        $time = $this->showTime();
        return $html.$time;
    }
}

shell
ab -c 100 -n 1000 -k http://127.0.0.1/index/
 
Requests per second
Time per request (mean)
Time per request (mean, across all concurrent requests)

运行方式
Swoole EventTCP Swoole SelectTCP Swoole BlockTCP Apache/Prefork
单进程
571.70 [#/sec] 174.916 [ms] 1.749 [ms] 659.01 [#/sec]
151.743 [ms]
1.517 [ms]
561.24 [#/sec]
178.178 [ms]
1.782
80.57
1241.083 [ms]
12.411 [ms]
4进程
1153.63 [#/sec]
86.683 [ms]
0.867 [ms]
1010.08 [#/sec]
99.002 [ms]
0.990 [ms]
1094.58 [#/sec]
91.359 [ms]
0.914 [ms]

apache下居然也有这么好的效率, 留个爪子.以后好用

使用php编程的同学都希望自己写的php代码最高效率执行,特别是初学者还没掌握的时候,现在我从网上收集了50个提高php编程执行效率的方法,希望对大家有用

1、用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加上了双引号)。

2、如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。

3、$row[’id’] 的速度是$row[id]的7倍。

4、echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接,比如echo $str1,$str2。

5、在执行for循环之前确定最大循环数,不要每循环一次都计算最大值,最好运用foreach代替。

6、注销那些不用的变量尤其是大数组,以便释放内存。

7、尽量避免使用__get,__set,__autoload。

8、require_once()代价昂贵。

9、include文件时尽量使用绝对路径,因为它避免了PHP去include_path里查找文件的速度,解析操作系统路径所需的时间会更少。

10、如果你想知道脚本开始执行(译注:即服务器端收到客户端请求)的时刻,使用$_SERVER[‘REQUEST_TIME’]要好于time()。

11、函数代替正则表达式完成相同功能。

12、str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。

13、如果一个字符串替换函数,可接受数组或字符作为参数,并且参数长度不太长,那么可以考虑额外写一段替换代码,使得每次传递参数是一个字符,而不是只写一行代码接受数组作为查询和替换的参数。

14、使用选择分支语句(译注:即switch case)好于使用多个if,else if语句。

15、用@屏蔽错误消息的做法非常低效,极其低效。

16、打开apache的mod_deflate模块,可以提高网页的浏览速度。

17、数据库连接当使用完毕时应关掉,不要用长连接。

18、错误消息代价昂贵。

19、在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。

20、递增一个全局变量要比递增一个局部变量慢2倍。

21、递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。

22、递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9至10倍。

23、仅定义一个局部变量而没在函数中调用它,同样会减慢速度(其程度相当于递增一个局部变量)。PHP大概会检查看是否存在全局变量。

24、方法调用看来与类中定义的方法的数量无关,因为我(在测试方法之前和之后都)添加了10个方法,但性能上没有变化。

25、派生类中的方法运行起来要快于在基类中定义的同样的方法。

26、调用带有一个参数的空函数,其花费的时间相当于执行7至8次的局部变量递增操作。类似的方法调用所花费的时间接近于15次的局部变量递增操作。

27、Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。尽量多用静态HTML页面,少用脚本。

28、除非脚本可以缓存,否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能,以免除编译开销。

29、尽量做缓存,可使用memcached。memcached是一款高性能的内存对象缓存系统,可用来加速动态Web应用程序,减轻数据库负载。对运算码 (OP code)的缓存很有用,使得脚本不必为每个请求做重新编译。

30、当操作字符串并需要检验其长度是否满足某种要求时,你想当然地会使用strlen()函数。此函数执行起来相当快,因为它不做任何计算,只返回在zval 结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数,多多少少会有些慢,因为函数调用会经过诸多步骤,如字母小写化(译注:指函数名小写化,PHP不区分函数名大小写)、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用isset() 技巧加速执行你的代码。(举例如下)if (strlen($foo) < 5) { echo “Foo is too short”$$ }(与下面的技巧做比较)if (!isset($foo{5})) { echo “Foo is too short”$$ }调用isset()恰巧比strlen()快,因为与后者不同的是,isset()作为一种语言结构,意味着它的执行不需要函数查找和字母小写化。也就是说,实际上在检验字符串长度的顶层代码中你没有花太多开销。

31、当执行变量$i的递增或递减时,$i++会比++$i慢一些。这种差异是PHP特有的,并不适用于其他语言,所以请不要修改你的C或Java代码并指望它们能立即变快,没用的。++$i更快是因为它只需要3条指令(opcodes),$i++则需要4条指令。后置递增实际上会产生一个临时变量,这个临时变量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种,正如Zend的PHP优化器所作的那样。牢记这个优化处理不失为一个好主意,因为并不是所有的指令优化器都会做同样的优化处理,并且存在大量没有装配指令优化器的互联网服务提供商(ISPs)和服务器。

32、并不是事必面向对象(OOP),面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。

33、并非要用类实现所有的数据结构,数组也很有用。

34、不要把方法细分得过多,仔细想想你真正打算重用的是哪些代码?

35、当你需要时,你总能把代码分解成方法。

36、尽量采用大量的PHP内置函数。

37、如果在代码中存在大量耗时的函数,你可以考虑用C扩展的方式实现它们。

38、评估检验(profile)你的代码。检验器会告诉你,代码的哪些部分消耗了多少时间。Xdebug调试器包含了检验程序,评估检验总体上可以显示出代码的瓶颈。

39、mod_zip可作为Apache模块,用来即时压缩你的数据,并可让数据传输量降低80%。

40、在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情况下,尽量用file_get_contents,因为他的效率高得多!但是要注意file_get_contents在打开一个URL文件时候的PHP版本问题;

41、尽量的少进行文件操作,虽然PHP的文件操作效率也不低的;

42、优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作(在update上,我被恶批过);

43、尽可能的使用PHP内部函数(但是我却为了找个PHP里面不存在的函数,浪费了本可以写出一个自定义函数的时间,经验问题啊!);

44、循环内部不要声明变量,尤其是大变量:对象(这好像不只是PHP里面要注意的问题吧?);

45、多维数组尽量不要循环嵌套赋值;

46、在可以用PHP内部字符串操作函数的情况下,不要用正则表达式;

47、foreach效率更高,尽量用foreach代替while和for循环;

48、用单引号替代双引号引用字符串;

49、“用i+=1代替i=i+1。符合c/c++的习惯,效率还高”;

50、对global变量,应该用完就unset()掉;

[!--infotagslink--]

相关文章

  • JS中artdialog弹出框控件之提交表单思路详解

    artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口。本文给大家介绍JS中artdialog弹出框控件之提交表单思路详解,对本文感兴趣的朋友一起学习吧...2016-04-19
  • 使用JQuery实现Ctrl+Enter提交表单的方法

    有时候我们为了省事就操作键盘组合键去代替使用鼠标,我们今天就使用JQuery实现Ctrl+Enter提交表单。我们发帖时,在内容输入框中输入完内容后,可以点击“提交”按钮来发表内容。可是,如果你够“懒”,你可以不用动鼠标,只需按...2015-10-23
  • vscode搭建STM32开发环境的详细过程

    这篇文章主要介绍了vscode搭建STM32开发环境的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-02
  • 基于JavaScript实现表单密码的隐藏和显示出来

    为了网站的安全性,很多朋友都把密码设的比较复杂,但是如何密码不能明显示,不知道输的是对是错,为了安全起见可以把密码显示的,那么基于js代码如何实现的呢?下面通过本文给大家介绍JavaScript实现表单密码的隐藏和显示,需要的朋友参考下...2016-03-03
  • Python运行提示缺少模块问题解决方案

    这篇文章主要介绍了Python运行提示缺少模块问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-10
  • Perl模块编写说明

    这两天在用Perl编写一些监控脚本,其实写代码也是一件挺有意思的事情,就是挺废时间的。而且,由于语法不太熟,基本想到一个东西都要先Google一下看怎么实现。...2020-06-29
  • 安卓开发之Intent传递Object与List教程

    下面我们一起来看一篇关于 安卓开发之Intent传递Object与List的例子,希望这个例子能够为各位同学带来帮助。 Intent 不仅可以传单个的值,也可以传对象与数据集合...2016-09-20
  • php微信公众账号开发之五个坑(二)

    这篇文章主要为大家详细介绍了php微信公众账号开发之五个坑,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-02
  • 如何设计一个安全的API接口详解

    在日常开发中,总会接触到各种接口,前后端数据传输接口,第三方业务平台接口,下面这篇文章主要给大家介绍了关于如何设计一个安全的API接口的相关资料,需要的朋友可以参考下...2021-08-12
  • react使用antd表单赋值,用于修改弹框的操作

    这篇文章主要介绍了react使用antd表单赋值,用于修改弹框的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29
  • Python PyPDF2模块安装使用解析

    这篇文章主要介绍了Python PyPDF2模块安装使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-04-22
  • html表单提交中method请求Get和Post区别详解

    在html表单提交中method请求Get和Post区别其实很显示的,get提交会是url形式的并且数据量不能太多,而post数据是在浏览器url看不到的并且可以是大数据量而且get安全性非...2016-09-20
  • 微信开发生成带参数的二维码的讲解

    在微信公众号平台开发者那里,在“账号管理”那里,有一项功能是“生成带参数的二维码”,通过这儿生成的二维码,只要通过微信扫一扫之后,会把事件自动推送到微...2016-05-19
  • 微信小程序 PHP后端form表单提交实例详解

    这篇文章主要介绍了微信小程序 PHP后端form表单提交实例详解的相关资料,需要的朋友可以参考下...2017-01-16
  • 解决antd Form 表单校验方法无响应的问题

    这篇文章主要介绍了解决antd Form 表单校验方法无响应的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-28
  • 基于Bootstrap实现Material Design风格表单插件 附源码下载

    Jquery Material Form Plugin是一款基于Bootstrap的Material Design风格的jQuery表单插件。这篇文章主要介绍了基于Bootstrap的Material Design风格表单插件附源码下载,感兴趣的朋友参考下...2016-04-19
  • BootStrap栅格系统、表单样式与按钮样式源码解析

    这篇文章主要为大家详细解析了BootStrap栅格系统、表单样式与按钮样式源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-01-23
  • vue2 中如何实现动态表单增删改查实例

    本篇文章主要介绍了vue2 中如何实现动态表单增删改查实例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...2017-06-15
  • c#通用登录模块分享

    这是一款简单的ASP.NETC#注册登录模块制作思路,非常简单实用,虽然没怎么考虑登陆的安全性,但作为C#的朋友学习交流使用。...2020-06-25
  • Chrome插件开发系列一:弹窗终结者开发实战

    从这一节开始,我们将从零开始打造我们的chrome插件工具库,第一节我们将讲一下插件开发的基础知识并构建一个简单但却很实用的插件,在构建之前,我们先简单的了解一下插件以及插件开发的基础知识...2020-10-03