链接最好放在公众号里php 数组循环,过期后可以更改,所以这也是文章中不收录的原因。 请看清楚这段话:如有需要,可以关注“PHP自学中心”,回复相应关键词,获取链接并提取代码。感谢您的支持和信任
Yii2视频教程
链接:https://pan.baidu.com/s/1kU6fbKz
密码:本公众号里回复关键词:yii2
文章正文
本文实例为大家分享php彩票概率算法,可用于刮刮卡、大转盘等中奖算法。 使用方法非常简单。 代码中有详细的注释供大家参考。 具体内容如下
/*
* 经典的概率算法,
* $proArr是一个预先设置的数组,
* 假设数组为:array(100,200,300,400),
* 开始是从1,1000 这个概率范围内筛选第一个数是否在他的出现概率范围之内,
* 如果不在,则将概率空间,也就是k的值减去刚刚的那个数字的概率空间,
* 在本例当中就是减去100,也就是说第二个数是在1,900这个范围内筛选的。
* 这样 筛选到最终,总会有一个数满足要求。
* 就相当于去一个箱子里摸东西,
* 第一个不是,第二个不是,第三个还不是,那最后一个一定是。
* 这个算法简单,而且效率非常高,
* 这个算法在大数据量的项目中效率非常棒。
*/
function get_rand($proArr) {
$result = '';
//概率数组的总概率精度
$proSum = array_sum($proArr);
//概率数组循环
foreach ($proArr as $key => $proCur) {
$randNum = mt_rand(1, $proSum);
if ($randNum <= $proCur) {
$result = $key;
break;
} else {
$proSum -= $proCur;
}
}
unset ($proArr);
return $result;
}
颁奖场
这里的奖励是一个二维数组。 您可以自己组装数据,也可以从后台将数据存储到数据库中,然后读取。 请记住php 数组循环,它是一个二维数组。
/*
* 奖项数组
* 是一个二维数组,记录了所有本次抽奖的奖项信息,
* 其中id表示中奖等级,prize表示奖品,v表示中奖概率。
* 注意其中的v必须为整数,你可以将对应的 奖项的v设置成0,即意味着该奖项抽中的几率是0,
* 数组中v的总和(基数),基数越大越能体现概率的准确性。
* 本例中v的总和为100,那么平板电脑对应的 中奖概率就是1%,
* 如果v的总和是10000,那中奖概率就是万分之一了。
*
*/
$prize_arr = array(
'0' => array('id'=>1,'prize'=>'平板电脑','v'=>1),
'1' => array('id'=>2,'prize'=>'数码相机','v'=>5),
'2' => array('id'=>3,'prize'=>'音箱设备','v'=>10),
'3' => array('id'=>4,'prize'=>'4G优盘','v'=>12),
'4' => array('id'=>5,'prize'=>'10Q币','v'=>22),
'5' => array('id'=>6,'prize'=>'下次没准就能中哦','v'=>50),
);
前端请求数据
每次后端请求数据,比如刮刮卡,转动转盘,循环发送奖励。
/*
* 每次前端页面的请求,PHP循环奖项设置数组,
* 通过概率计算函数get_rand获取抽中的奖项id。
* 将中奖奖品保存在数组$res['yes']中,
* 而剩下的未中奖的信息保存在$res['no']中,
* 最后输出json个数数据给前端页面。
*/
foreach ($prize_arr as $key => $val) {
$arr[$val['id']] = $val['v'];
}
$rid = get_rand($arr); //根据概率获取奖项id
$res['yes'] = $prize_arr[$rid-1]['prize']; //中奖项
unset($prize_arr[$rid-1]); //将中奖项从数组中剔除,剩下未中奖项
shuffle($prize_arr); //打乱数组顺序
for($i=0;$i<count($prize_arr);$i++){
$pr[] = $prize_arr[$i]['prize'];
}
$res['no'] = $pr;
print_r($res);
文章正文
PHP的设计理念和特点 PHP的核心框架
PHP核心架构如右图,从下到上可以简单分为四层:
PHP的执行过程
PHP实现了典型的动态语言执行过程:接收到一段代码后,经过词法分析、语法分析等阶段,将源程序翻译成指令(操作码),然后ZEND虚拟机依次执行这些指令完毕。 PHP本身是用C实现的,所以最终调用的都是C函数。 其实PHP可以看成是C语言开发的软件。
PHP执行的核心就是一一翻译后的指令,即操作码。
操作码是PHP程序执行的最基本单位。 一个操作码由两个参数(op1、op2)、返回值和处理函数组成。 PHP程序最终被翻译成一系列操作码处理函数。
几种常见的处理函数:
Zend 引擎简介
端引擎作为PHP的核心,有很多经典的设计机制,主要有:
4.1 实现HashTable数据组织:
HashTable 是 Zend 的核心数据结构。 几乎所有常用功能都是用PHP实现的。 我们所知道的PHP领域就是它的典型应用。 而且,zend内部,函数符号表、全局变量等功能也是基于hashtable实现的。
Zendhashtable实现了一种典型的哈希表哈希结构,同时通过附加一个单向数组提供了正向和反向遍历字段的功能。其结构如右图所示
可以看到,hashtable中既有key->value的哈希结构,也有单向数组模式,这样就可以非常方便地支持快速查找和线性遍历。
哈希结构:Zend的哈希结构是典型的哈希表模型,它以数组的形式解决冲突。 需要注意的是,zend的hashtable是一种自减的数据结构。 当哈希表的数量已满时,它会动态扩展其容量2倍并重新定位元素。 两者的初始大小均为 8。 另外,在进行key->value快速查找时,zend本身也做了一些优化,通过以空间换时间来提高速度。 例如,在每个元素中,使用一个变量nKeyLength来标记按键的粗细,以便快速判断。
单向数组:Zendhashtable 通过数组结构实现元素的线性遍历。 理论上来说,使用双向数组进行遍历就足够了。 使用单向数组的主要目的是快速删除和防止遍历。 Zendhashtable 是一个复合结构。 当用作形式参数时,它支持常见的关联链表,也可以用作顺序索引号,甚至允许两者混合。
PHP关联字段:关联字段是典型的hash_table应用。 一次查询过程会经过以下步骤(从代码中可以看出,这是一个普通的哈希查询过程,减少了一些快速判断,以加快查找速度):
getKeyHashValue h;
index = n & nTableMask;
Bucket *p = arBucket[index];
while (p) {
if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
RETURN p->data;
}
p=p->next;
}
RETURN FALTURE;
PHP索引字段:索引字段是我们常见的字段,通过下标访问。 比如arr[0],ZendHashTable内部进行了归一化,同时将hash值和nKeyLength(0)也赋值给了索引类型key。 内部成员变量nNextFreeElement是当前分配的最大id,每次push后都会手动加1。 正是这些规范化过程让 PHP 实现了关联和非关联的混合。 由于push操作的特殊性,PHP链表中索引键的顺序并不是由下标的大小决定的php 判断字符串,而是由push的顺序决定的。如arr[1]=2; arr[2]=3; 对于 double 类型的 key,ZendHashTable 会把他当作索引 key
4.2 PHP变量实现原理:
PHP是弱类型语言,并不严格区分变量的类型。 PHP在声明变量时不需要指定类型。 PHP 可能在程序执行期间执行变量类型的隐式转换。 与其他强类型语言一样,程序中也可以进行显式类型转换。 PHP变量可以分为简单类型(int、string、bool)、集合类型(array、resource、object)和常量(const)。 上面所有的变量都是底层相同的结构zval。
Zval是zend中另一个特别重要的数据结构。 它用于标记和实现PHP变量。 其数据结构如下:
Zval结构主要由三部分组成:
type:指定变量描述的类型(整数、字符串、数组等)
refcount&is_ref:用于实现引用计数(前面详细介绍过)
value:核心部分,存储变量的实际数据
Zvalue用于保存变量的实际数据。 由于要存储多种类型,所以zvalue是一个union,它也实现了弱类型。
PHP变量类型与其实际存储的对应关系如下:
IS_LONG -> lvalue
IS_DOUBLE -> dvalue
IS_ARRAY -> ht
IS_STRING -> str
IS_RESOURCE -> lvalue
4.2.1 整数和浮点变量
整数和浮点数是PHP中的基本类型之一,也是简单的变量。 对于整数和浮点数,将对应的值直接存储在zvalue中。 其类型分别为long和double。
从zvalue结构可以看出,对于整数类型,与C等强类型语言不同,PHP不区分int、unsignedint、long、longlong等类型。 对于它来说,只有一种整数类型,那就是长整型。 由此可见,在PHP上,整数的取值范围是由编译器的位数决定的,而不是固定的。
对于浮点数来说,和整数类似,它不区分float和double,而只区分double的一种。
在PHP中,如果整数范围超出范围怎么办? 在这些情况下,它将被手动转换为 double 类型。 这点一定要小心,因为很多花招都是由此形成的。
4.2.2 字符变量
与整数一样,字符变量是 PHP 中的原始类型和简单变量。 从zvalue结构可以看出,在PHP中,字符串是由指向实际数据的指针和宽度结构组成的,与C++中的字符串类似。 因为厚度是用实际变量表示的,与c不同,它的字符串可以是2补码数据(包括),而在PHP中,求字符串宽度strlen是一个O(1)的操作。
当进行添加、修改、追加字符串操作时,PHP会重新分配显存来生成新的字符串。 最后,出于安全考虑,PHP在生成字符串时仍然会在末尾添加
常见的字符串拼接方法及速度对比:
假设有4个变量如下:strA='123';strB='456';intA=123;intB=456;
现对以下字符串拼接方式进行对比和说明:
1 res = strA.strB 且 res = "strAstrB"
在这些情况下,zend会重新malloc一块显存并进行相应处理,其速度也正常。
2strA=strA.strB
这些是最快的,zend会直接根据当前strA进行relloc,防止重复复制
3res=intA.intB
这些速度很慢,因为需要隐式格式转换,在实际编程中要注意尽量避免
4strA=sprintf(“%s%s”,strA,strB);
这将是最慢的形式,因为sprintf不是PHP中的语言结构,它需要花费大量时间来识别和处理格式,而且它的机制也是malloc。 但sprintf的形式可读性最强,实际中可以根据具体情况灵活选择。
4.2.3 字段变量
PHP的链表自然是通过ZendHashTable来实现的。
如何实现foreach操作? 链表的foreach是通过遍历哈希表中的单向数组来完成的。 对于索引字段,foreach遍历的效率比for高很多,并且省略了key->value的查找。 计数操作直接调用HashTable->NumOfElements,O(1)操作。 对于像 '123' 这样的字符串,zend 会将其转换为整数形式。 arr['123'] 和 arr[123] 等效
4.2.4 资源变量
资源类型变量是PHP中最复杂的变量,也是复合结构。
PHP的zval可以表示很多种数据类型,很难完全描述自定义数据类型。 由于没有有效的方法来绘制此类复合结构,因此无法在其上使用传统运算符。 要解决这个问题,只需要通过本质上任意的标识符(标签)来引用指针即可。 这些方法称为资源。
在zval中,对于资源来说,lval作为指针,直接指向资源所在的地址。 资源可以是任意组合结构,我们熟悉的mysqli、fsock、memcached等都是资源。
如何使用资源:
1 注册:对于自定义数据类型,您希望将其用作资源。 首先,它需要注册,zend 会给它分配一个全局唯一的标识符。
2 获取资源变量:对于资源,zend维护一个id->实际数据的hash_tale。 对于资源,zval 中仅记录其 id。 取的时候,通过id找到hash_table中的具体值并返回。
3 资源破坏:资源的数据类型多种多样。 Zend 本身没有办法销毁它。 因此,用户在注册资源时需要提供销毁函数。 当unset资源时,zend调用相应的函数来完成销毁。 同时将其从全局资源表中删除。
资源可以持续存在多年,不仅是在引用它的所有变量超出范围之后,而且甚至在请求结束并形成新请求之后也是如此。 此类资源称为持久资源,因为它们在 SAPI 的整个生命周期中持续存在,除非被故意破坏。 很多情况下,持久化资源可以在一定程度上提高性能。 比如我们常见的mysql_pconnect,持久化资源通过pemalloc分配显存,这样请求结束时就不会被释放。 对于zend来说,两者没有区别。
4-3. PHP 变量管理 - 引用计数和写时复制:
引用计数在显存回收、字符串操作等方面应用尤其广泛。Zval的引用计数是通过成员变量is_ref和ref_count来实现的。 通过引用计数,多个变量可以共享相同的数据。 防止频繁复印造成的大量消耗。 zend在进行形参操作时,将变量指向与ref_count++相同的zval,而unset操作时,对应的ref_count-1。 只有当ref_count减为0时,才会执行实际的销毁操作。 如果是引用参数,zend 会将 is_ref 更改为 1。
PHP变量通过引用计数实现变量共享数据,那么如果其中一个变量值改变了怎么办? 当尝试写入一个变量时,如果Zend发现该变量指向的zval被多个变量共享,它将复制一个ref_count为1的zval,并减少原始zval的refcount。 这个过程称为“zval分离”。 可见zend只有在发生写操作时才会进行复制操作,因此也称为copy-on-write(写时复制)
对于引用变量,其要求与非引用类型相反。 引用参数的变量必须是绑定的,改变一个变量会改变所有绑定的变量。
4-4. PHP局部变量和全局变量的实现:
PHP中局部变量和全局变量是如何实现的? 对于一个请求,PHP随时可以看到两个符号表(symbol_table和active_symbol_table),后者用于维护全局变量。 前者是指向当前活动变量符号表的指针。 当程序进入一个函数时,zend会为其分配一个符号表x,并将active_symbol_table指向a。 通过这种方法,实现了全局变量和局部变量的区分。
获取变量值:PHP的符号表是通过hash_table实现的,为每个变量分配一个唯一的标签。 获取时根据标签从表中找到对应的zval并返回。
在函数中使用全局变量:在函数中,我们可以通过显式声明global来使用全局变量。 在active_symbol_table中创建对symbol_table中同名变量的引用(引用变量的值需要更新你就一起更新)php 判断字符串,如果symbol_table中没有同名变量,则会首先创建的。
以上就是文章的全部内容。 有学习和经验交流的可以加小编为好友。 如果有技术问题可以一起解释、交流。 如果你是PHP的,小编还可以拉你进Momo技术群交流学习!
让学习成为一种习惯
学习|交流|分享|文章