看到这个主题大家知道我今天要说的是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);}

데이터베이스 스토리지 세션 사용의 주요 장점에는 지속성, 확장 성 및 보안이 포함됩니다. 1. 지속성 : 서버가 다시 시작 되더라도 세션 데이터는 변경되지 않아도됩니다. 2. 확장 성 : 분산 시스템에 적용하여 세션 데이터가 여러 서버간에 동기화되도록합니다. 3. 보안 : 데이터베이스는 민감한 정보를 보호하기 위해 암호화 된 스토리지를 제공합니다.

SessionHandlerInterface 인터페이스를 구현하여 PHP에서 사용자 정의 세션 처리 구현을 수행 할 수 있습니다. 특정 단계에는 다음이 포함됩니다. 1) CustomsessionHandler와 같은 SessionHandlerInterface를 구현하는 클래스 만들기; 2) 인터페이스의 방법 (예 : Open, Close, Read, Write, Despare, GC)의 수명주기 및 세션 데이터의 저장 방법을 정의하기 위해 방법을 다시 작성합니다. 3) PHP 스크립트에 사용자 정의 세션 프로세서를 등록하고 세션을 시작하십시오. 이를 통해 MySQL 및 Redis와 같은 미디어에 데이터를 저장하여 성능, 보안 및 확장 성을 향상시킬 수 있습니다.

SessionId는 웹 애플리케이션에 사용되는 메커니즘으로 사용자 세션 상태를 추적합니다. 1. 사용자와 서버 간의 여러 상호 작용 중에 사용자의 신원 정보를 유지하는 데 사용되는 무작위로 생성 된 문자열입니다. 2. 서버는 쿠키 또는 URL 매개 변수를 통해 클라이언트로 생성하여 보낸다. 3. 생성은 일반적으로 임의의 알고리즘을 사용하여 독창성과 예측 불가능 성을 보장합니다. 4. 실제 개발에서 Redis와 같은 메모리 내 데이터베이스를 사용하여 세션 데이터를 저장하여 성능 및 보안을 향상시킬 수 있습니다.

JWT 또는 쿠키를 사용하여 API와 같은 무국적 환경에서 세션을 관리 할 수 있습니다. 1. JWT는 무국적자 및 확장 성에 적합하지만 빅 데이터와 관련하여 크기가 크다. 2. 쿠키는보다 전통적이고 구현하기 쉽지만 보안을 보장하기 위해주의해서 구성해야합니다.

세션 관련 XSS 공격으로부터 응용 프로그램을 보호하려면 다음 조치가 필요합니다. 1. 세션 쿠키를 보호하기 위해 Httponly 및 Secure 플래그를 설정하십시오. 2. 모든 사용자 입력에 대한 내보내기 코드. 3. 스크립트 소스를 제한하기 위해 컨텐츠 보안 정책 (CSP)을 구현하십시오. 이러한 정책을 통해 세션 관련 XSS 공격을 효과적으로 보호 할 수 있으며 사용자 데이터가 보장 될 수 있습니다.

PHP 세션 성능을 최적화하는 방법 : 1. 지연 세션 시작, 2. 데이터베이스를 사용하여 세션을 저장, 3. 세션 데이터 압축, 4. 세션 수명주기 관리 및 5. 세션 공유 구현. 이러한 전략은 높은 동시성 환경에서 응용의 효율성을 크게 향상시킬 수 있습니다.

THESESSION.GC_MAXLIFETIMESETTINGINSTTINGTINGSTINGTERMINESTERMINESTERSTINGSESSIONDATA, SETINSECONDS.1) IT'SCONFIGUDEDINPHP.INIORVIAINI_SET ()

PHP에서는 Session_Name () 함수를 사용하여 세션 이름을 구성 할 수 있습니다. 특정 단계는 다음과 같습니다. 1. Session_Name () 함수를 사용하여 Session_Name ( "my_session")과 같은 세션 이름을 설정하십시오. 2. 세션 이름을 설정 한 후 세션을 시작하여 세션을 시작하십시오. 세션 이름을 구성하면 여러 응용 프로그램 간의 세션 데이터 충돌을 피하고 보안을 향상시킬 수 있지만 세션 이름의 독창성, 보안, 길이 및 설정 타이밍에주의를 기울일 수 있습니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경

안전한 시험 브라우저
안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)
