被忽略的魔法——php引用之推迟赋值(后期数据延迟绑定)
被忽略的魔法——php引用之延迟赋值(后期数据延迟绑定)
看到这个主题大家知道我今天要说的是php的变量引用特性,但是延迟赋值又是怎么回事呢?这个主要是我近期优化一些功能时的一个想法,我觉得还算不错,就打算记录下来。看一下下面的伪代码:
// 这段代码有人会说为啥不用联表,因为有些业务需求不用联表的效率是联表的3到20倍// 我的项目里基本都是此类写法,比之前联表效率提升很多$a = DB::query("select id from a");$aid = "";foreach($a as $v){ $aid .= $v['id'].','; }$aid = substr($aid, 0 , -1);if($aid){ $b = DB::query("select * from b where aid in ({$aid})"); // 此处省略}
之所以用这段代码举例,因为类似这样的代码很多,大家比较容易理解,但不一定适合用后期延迟赋值,因为这样更容理解,且效率差不多,不过可以和后期延迟赋值形成鲜明对比,让大家更容理解下面的实现的方式。
看完上面的例子我们再看一个复杂的需求,要求数据是获取一人的最近10篇文章列表,且读取每篇文章5条评论,并包含文章发起者和评论人的id,姓名,把是数据打包成指定格式的json返回给客户端,看下面的代码:
// 这种需求用联表获取用户信息远没有搜集用户id做in查询效率高$data = array();$article = DB::query("select id,uid,title,content from article where uid={$_GET['uid']} order by id desc limit 10");foreach($article as $v){ $uid = $v['uid']; $comment = DB::query("select id,uid,content from comment where aid={$v['id']} order by id asc limit 5"); foreach($comment as $value){ $uid .= ','.$value['uid']; } // 这里第二个参数我们要求DB类返回的数组以uid为索引 $member = DB::query("select uid,username from user where uid in({$uid})", 'uid'); $commentList = array(); $data[] = array( 'id' => $v['id'], 'title' => $v['title'], 'content' => $v['content'], 'uid' => $v['uid'], 'username' => $member[$v['uid']]['username'], 'comment' => &$commentList ); foreach($comment as $value){ $commentList[] = array( 'id' => $value['id'], 'content' => $value['content'], 'uid' => $value['uid'], 'username' => $member[$value['uid']]['username'] ) }} echo json_encode($data);exit;
细心看这段代码就会发现其中$data[]['comment']的值最开始就引用了变量$commentList,之后在后面更改了$commentList的值,同时导致$data[]['comment']值跟着一起发生了改变,这里也是后期延迟赋值,但是比较简单,可以据此了解一下这个实现原理。
我相信大多数人都写过类似的代码,也很少有人觉得这段代码会有问题。我来分析一下这块的逻辑,评论信息因为要每篇文章获取5条,这个没法用简单的sql合并成一条,由于需求只是获取10篇文章,写复杂的sql处理反而不如循环查询的效率(如果你内网延迟较低的情况下),为啥说复杂sql的处理效率慢,如果你考虑的是几千条数据都一样没啥需要注意,但是如果处理的是千万级别的数据量,复杂sql很多情况下不如简单的sql效率高,那么这里就采用循环查询没法继续优化。但是我们看用户信息也在循环里进行查询,这个很不好了,我的项目组里很不希望见到这样的代码的,10篇帖子都是一个人发起的,近50条评论会有很多活跃用户的数据,这样每次循环查询其实查询到重复用户信息的概率非常高,在一个业务逻辑里最好不要从数据库获取重复信息而是复用。如何能让让用户信息达到复用呢?可以在组装最终数据前循环获取文章的评论信息,之后收集用户id,然后再获取用户信息,之后组装最终的数据。这是一种比较简单的解决方案,不是我们今天的重点,下面看一种优雅的处理方式——延迟赋值。
// 这种需求用联表获取用户信息远没有搜集用户id做in查询效率高$data = array();$article = DB::query("select id,uid,title,content from article where uid={$_GET['uid']} order by id desc limit 10");$member = array();foreach($article as $v){ $comment = DB::query("select id,uid,content from comment where aid={$v['id']} order by id asc limit 5"); $commentList = array(); $data[] = array( 'id' => $v['id'], 'title' => $v['title'], 'content' => $v['content'], 'uid' => $v['uid'], 'username' => &$member[$v['uid']]['username'], 'comment' => &$commentList ); foreach($comment as $value){ $commentList[] = array( 'id' => $value['id'], 'content' => $value['content'], 'uid' => $value['uid'], 'username' => &$member[$value['uid']]['username'] ) }}$uid = array_keys($member);if($uid){ $uid = implode(',', $uid); $user = DB::query("select uid,username from user where uid in({$uid})", 'uid'); foreach($member as $uid => $value){ $member[$uid]['username'] = $user[$uid]['username']; } unset($member,$user);}echo json_encode($data);exit;
这段代码和之前不太一样了,最明显的就是最下面多了一段代码,而且暂时还不知道究竟是干嘛,好像没啥用,我们一步步的看看,首先在循环文章数据前初始化了一个变量$member = array();之后在循环里少了$uid的赋值,以及循环收集评论人的id,并且查询用户数据的sql也不见了,好像到了最下面那段看不懂的代码地方。仔细找了找还发现&$member[$v['uid']]['username']和&$member[$value['uid']]['username']地方多了&引用符号,这就是为啥循环里少了写代码的奥秘。回想一下之前发现$commentList被引用之后在后面进行赋值的,并且改变了$data[]['comment']。这的道理是一样的,先不查询用户信息,只进行一个空的引用,在引用一个不存在的变量时php会先创建这个变量,例如&$member[$v['uid']]['username'],php检测$member是一个数组已经声明,但是$member[$v['uid']]['username']不存在就在内存创建并且值为null。
当循环完文章数据后打印会发现username的信息都是null,当然之前并没用用户信息,php在引用赋值的时候帮我们给了一个null值。之后通过$uid = array_keys($member);获取所有用户的id信息,
为什么array_keys能获取用户id,因为php在引用的时候帮我们创建了$member数组呀,注意一下这里的uid是不重复的哟,之后我们去user表用in检索用户信息,一定注意这里不能把返回的数据赋值给$member因为之前的数据都是引用$member里的数据,如果这里覆盖了$member,内存里两个变量的地址就不一样了,相当于重新创建了一个数组,我们这里赋值给$user,下面的循环是干什么的,当然是修改之前被引用数据的赋值了,我们循环$member变量把$user[$uid]['username']赋值给$member[$uid]['username'],从而改变引用变量的值。在我们把数据绑定到引用变量后千万不要忽略用uset把$member删除了,主要是防止之后的代码里出现操作$member变量的代码,不小心就会把之前绑定好的数据覆盖掉。为啥删除$member之后绑定的数据没有丢失,主要是引用的特性,当多个变量引用一个内存地址时,删除其中一个变量不影响其它变量,除非把所有变量都删除,才会真的删除内存里的数据。php手册是这么解释的“当 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了”。unset($user);只是因为$user是一个临时变量,使用完可以直接从内存释放了。
关于这种编程方式我命名为后期数据延迟绑定,之所以标题是延迟变量赋值主要是让大家便于理解。Php中引用的作用非常广泛,本文所举的例子也只局部的一种使用方法,用来解决编程中遇到类似业务需求的一种处理方式,当然后期数据延迟绑定的编程方法也有很广的使用,希望大家不要局限在本文例子的场景上。针对本文例子是我们编程中最常用的一种问题,我编写了一个函数用来处理数据延迟绑定,减少每个地方都要编写数据绑定的逻辑。
/** * 数据延迟绑定通用方法 * * @access public * @param array $bindingVar 待绑定的变量 * @param array $data 待绑定的数据 * @param mixed $default 默认值 * @return void */function bindingData(&$bindingVar, $data, $default=''){ foreach($bindingVar as $key => $tmp){ foreach($tmp as $k => $v){ $bindingVar[$key][$k] = isset($data[$key][$k]) ? $data[$key][$k] : $default; } } unset($bindingVar);}
采用这个函数我们能把之前处理数据绑定的代码部分改成下面这样:
$uid = array_keys($member);if($uid){ $user = DB::query("select uid,username from user where uid in({$uid})", 'uid'); bindingData($member, $user); unset($member,$user);}

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

The message "Your organization has asked you to change your PIN" will appear on the login screen. This happens when the PIN expiration limit is reached on a computer using organization-based account settings, where they have control over personal devices. However, if you set up Windows using a personal account, the error message should ideally not appear. Although this is not always the case. Most users who encounter errors report using their personal accounts. Why does my organization ask me to change my PIN on Windows 11? It's possible that your account is associated with an organization, and your primary approach should be to verify this. Contacting your domain administrator can help! Additionally, misconfigured local policy settings or incorrect registry keys can cause errors. Right now

Windows 11 brings fresh and elegant design to the forefront; the modern interface allows you to personalize and change the finest details, such as window borders. In this guide, we'll discuss step-by-step instructions to help you create an environment that reflects your style in the Windows operating system. How to change window border settings? Press + to open the Settings app. WindowsI go to Personalization and click Color Settings. Color Change Window Borders Settings Window 11" Width="643" Height="500" > Find the Show accent color on title bar and window borders option, and toggle the switch next to it. To display accent colors on the Start menu and taskbar To display the theme color on the Start menu and taskbar, turn on Show theme on the Start menu and taskbar

By default, the title bar color on Windows 11 depends on the dark/light theme you choose. However, you can change it to any color you want. In this guide, we'll discuss step-by-step instructions for three ways to change it and personalize your desktop experience to make it visually appealing. Is it possible to change the title bar color of active and inactive windows? Yes, you can change the title bar color of active windows using the Settings app, or you can change the title bar color of inactive windows using Registry Editor. To learn these steps, go to the next section. How to change title bar color in Windows 11? 1. Using the Settings app press + to open the settings window. WindowsI go to "Personalization" and then

Do you see "A problem occurred" along with the "OOBELANGUAGE" statement on the Windows Installer page? The installation of Windows sometimes stops due to such errors. OOBE means out-of-the-box experience. As the error message indicates, this is an issue related to OOBE language selection. There is nothing to worry about, you can solve this problem with nifty registry editing from the OOBE screen itself. Quick Fix – 1. Click the “Retry” button at the bottom of the OOBE app. This will continue the process without further hiccups. 2. Use the power button to force shut down the system. After the system restarts, OOBE should continue. 3. Disconnect the system from the Internet. Complete all aspects of OOBE in offline mode

Taskbar thumbnails can be fun, but they can also be distracting or annoying. Considering how often you hover over this area, you may have inadvertently closed important windows a few times. Another disadvantage is that it uses more system resources, so if you've been looking for a way to be more resource efficient, we'll show you how to disable it. However, if your hardware specs can handle it and you like the preview, you can enable it. How to enable taskbar thumbnail preview in Windows 11? 1. Using the Settings app tap the key and click Settings. Windows click System and select About. Click Advanced system settings. Navigate to the Advanced tab and select Settings under Performance. Select "Visual Effects"

We all have different preferences when it comes to display scaling on Windows 11. Some people like big icons, some like small icons. However, we all agree that having the right scaling is important. Poor font scaling or over-scaling of images can be a real productivity killer when working, so you need to know how to customize it to get the most out of your system's capabilities. Advantages of Custom Zoom: This is a useful feature for people who have difficulty reading text on the screen. It helps you see more on the screen at one time. You can create custom extension profiles that apply only to certain monitors and applications. Can help improve the performance of low-end hardware. It gives you more control over what's on your screen. How to use Windows 11

Screen brightness is an integral part of using modern computing devices, especially when you look at the screen for long periods of time. It helps you reduce eye strain, improve legibility, and view content easily and efficiently. However, depending on your settings, it can sometimes be difficult to manage brightness, especially on Windows 11 with the new UI changes. If you're having trouble adjusting brightness, here are all the ways to manage brightness on Windows 11. How to Change Brightness on Windows 11 [10 Ways Explained] Single monitor users can use the following methods to adjust brightness on Windows 11. This includes desktop systems using a single monitor as well as laptops. let's start. Method 1: Use the Action Center The Action Center is accessible

The activation process on Windows sometimes takes a sudden turn to display an error message containing this error code 0xc004f069. Although the activation process is online, some older systems running Windows Server may experience this issue. Go through these initial checks, and if they don't help you activate your system, jump to the main solution to resolve the issue. Workaround – close the error message and activation window. Then restart the computer. Retry the Windows activation process from scratch again. Fix 1 – Activate from Terminal Activate Windows Server Edition system from cmd terminal. Stage – 1 Check Windows Server Version You have to check which type of W you are using
