php 语法和原理

来源:互联网 发布:北京白领公寓 知乎 编辑:程序博客网 时间:2024/06/15 11:39


global vs $_GLOBALS


1.global

在函数体内定义的global变量,函数体外可以使用,在函数体外定义的global变量不能在函数体内使用,


function f() 

global $a; 


$a = 456;
f(); 
echo $a;  //456


global $a; 
function f() 

$a = 456;

f(); 
echo $a; //empty
exit;


2.global vs $_GLOBALS


global 改变外部会改变内部  改变内部不会改变外部

$_GLOBALS 外部就是内部,所以改变外部就是改变内部,改变内部也改变外部


php语法中,很多人都认为global和$GLOBALS[]只是写法上面的差别,其实不然
根据官方的解释是
1.$GLOBALS[‘var’]是外部的全局变量本身
2.global $var是外部$var的同名引用或者指针。



举例说明一下: 

<?php
$var1 = 1;
$var2 = 2;
function test(){
$GLOBALS[‘var2′] = &$GLOBALS[‘var1′];
}
test();
echo $var2;

?>

正常打印结果为1



<?php
$var1 = 1;
$var2 = 2;
function test(){
global $var1,$var2;
$var2 = &$var1;
}
test();
echo $var2;

?>


意外打印结果为2

为什么会打印结果为2呢?其实就是因为$var1的引用指向了$var2的引用地址。导致实质的值没有改变。 
我们再来看一个例子吧。


<?php
$var1 = 1;
function test(){
unset($GLOBALS[‘var1′]);
}
test();
echo $var1;
?>

因为$var1被删除了,所以什么东西都没有打印


<?php
$var1 = 1;
function test(){
global $var1;
unset($var1);
}
test();
echo $var1;
?>


意外的打印了1。证明删除的只是别名|引用,起本身的值没有受到任何的改变
明白了吧?

也就是说global $var其实就是$var = &$GLOBALS[‘var’]。调用外部变量的一个别名而已



1.NULL  表示变量没有值


$a=null;

$b='value';

unset($b);

var_dump($a);直接赋值null

var_dump($b);$b被销毁了,null

var_dump($c);没有$c,null


2.数据类型转换:


bool(true 1  |false 0) and null(0) ==>int  float(int 转成 float后运算)

string==>int  float   字符串先转为数字后运算



3.预定义常量:

    

    1)__FUNCTION__: 函数名称(PHP 4.3.0 新加).自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写).在 PHP 4 中该值总是小写字母的.

    2)__FILE__: 文件的完整路径和文件名.如果用在包含文件中,则返回包含文件名.自 PHP 4.0.2 起,__FILE__ 总是包含一个绝对路径,而在此之前的版本有时会包含一个相对路径.
    3)__LINE__: 文件中的当前行号
    4)__CLASS__: 类的名称(PHP 4.3.0 新加).自 PHP 5 起本常量返回该类被定义时的名字(区分大小写).在 PHP 4 中该值总是小写字母的.
    5)__METHOD__: 类的方法名(PHP 5.0.0 新加).返回该方法被定义时的名字(区分大小写).
    6)DIRECTORY_SEPARATOR: windows下的是\和/,而LINUX下的是/,以前觉得既然windows,LINUX 都支持/,那都用成 / 得了,这是没错的.可是从这个例子可以看出,当要对路径字符串进行处理的时候,就比较危险了,所以最好还是用DIRECTORY_SEPARATOR吧.


4.运算符:

                算术  字符串  赋值  比较  逻辑  位  其他




php传值

1.静态 vs 引用

//静态 初值
class Child{
public $name;
//这里定义并初始化一个静态变量 $nums
public static $nums=0;
function __construct($name){
$this->name=$name;
}


public function join_game(){

//self::$nums 使用静态变量
self::$nums+=1;
echo $this->name."加入堆雪人游戏";

}
}


//创建三个小孩

$child1=new Child("李逵");
$child1->join_game();
$child2=new Child("张飞");
$child2->join_game();
$child3=new Child("唐僧");
$child3->join_game();


//看看有多少人玩游戏
echo "<br/> 有这".Child::$nums; 


//引用  内外
        function func1($a) {
       $a = $a + 1;
       }
       function func2(&$a) {
       $a = $a + 1;
       }
       $sample = 1;
       func1($sample);
       echo $sample; // 输出 1


       $sample = 1;
       func2($sample);
       echo $sample; // 输出 2 



2. $GLOBALS vs global

+$global 传参,$GLOBALS 赋值


$a = 1;
$b = 5;
function aa()
{
    global $a,$b;
    $b = &$a;
    $b = 10; 
}
aa();
echo $b;   //5
?>
 *
 * 
为什么$b 还是 5 ?
因为,如果在一个函数内部给一个声明为 global 的变量赋于一个引用,该引用只在函数内部可见。
可以通过使用 $GLOBALS 数组避免这一点:
 * 
 * 
<?php  
$var1 = "Example variable";  
$var2 = "";  
  
function global_references($use_globals)  
{  
    global $var1, $var2;  
    if (!$use_globals) {  
        $var2 =& $var1; // visible only inside the function  
    } else {  
        $GLOBALS["var2"] =& $var1; // visible also in global context  
    }  
}  
  
global_references(false);  
echo "var2 is set to '$var2'/n"; // var2 is set to ''  
global_references(true);  
echo "var2 is set to '$var2'/n"; // var2 is set to 'Example variable'  
?>   


+变量传递,两者结果是相同的,只是global要求变量名也必须相同,而引用就不用了,因为它是同名指向的
<?php  
function foo($a)  
{  
    global $a;
    $a++;  
}  
  
$a=5;  
foo($a);
echo $a;


function fooUse(&$var)  
{  
    $var++;  
}  
  
$a=5;  
fooUse($a);  
echo $a;
?>   


+global 从外面拿到里面来用的案例,(提示:global在函数外声明global,是拿不进来的)
//不在外面声明global,在函数内声明global后直接拿来在函数内局部使用的,
include('./lib.php');//$sys = array('default'=>'value');
function useGlobal(){
   global $sys; //不加global $sys ,函数里面无法打印出值
    var_dump($sys);
}


useGlobal();


function f() 


global $a;
$a=456; 


f('456'); 

var_dump( $a); //null

function give(&$value){
$value =4;
}

give($me);
var_dump($me);//4


3.foreach

error_reporting(0);
$arr = array(1,2,3);
foreach($arr as &$value){   
 $value .= '4';   
}


unset($value);  

var_dump($arr);



php原理

结构体的结构,决定了引用产生的相关问题,写时拷贝和引用计数和引用传值

1.变量结构体

struct_zval_struct {

  /* Variable information */

  zvalue_value value;  /*变量的值,是个联合体*/

  zend_uint refcount__gc; /*指向次数*/

  zend_uchar type;  /* 变量类型*/

  zend_uchar is_ref__gc; /*是否引用*/

};


type字段的值为以下常量

IS_NULL,IS_BOOL,IS_LONG,IS_DOUBLE

IS_STRING,IS_ARRAY,IS_OBJECT

IS_RESOURCE


联合体中的值

typedefunion _zvalue_value{

  long lval;  /* long value */

  double dval;  /* double value */

  struct{

  char *val;

  intlen;

  } str;

  HashTable*ht;  /* hash table value */

  zend_object_valueobj;

}zvalue_value;

联合中为什么只列出了5种值?

NULL不用,zval的type为IS_NULL即可

Bool以1,0存储在lval上

resource的type为resource,其resource的内容用long来标志(资源标记)




$str = 'hello' 就是is_string 并赋值为hello,同时加入符号表(变量名->zval结构体地址)


2.常量结构体:常量是全局有效的,它的哈希表只有一个EG

typedefstruct _zend_constant {

  zval value; //变量结构体

  int flags;   //标志,是否大小写敏感等

  char *name; //常量名

  uint name_len;

  int module_number;//模块名

}zend_constant;


3.内存管理和垃圾回收

PHP封装了对系统内存请求,不要直接用malloc直接请求内存

各种符号表全是hash表,如全局 局部 常量和函数符号表等的

引用计数器:

$a= 1;

$b= $a;//这个时候$a和$b同享一个结构体,只是recount_gc由1变成2

$b=6//写时拷贝,这时重新复制了了一个结构体,引用也变成了1,

$b= &$a;//引用传值,就是recount_gc增加了1,同时is_ref_gc由0变成1

$b=6//这时$b变了,也影响了$a,因为is_ref_gc为1,就直接修改value,而不是复制了一份



$a = 1;

$b = &$a;

$c = $b;

$a = 9;

a和b引用计数,所以直接变成9,但是c写时拷贝了,就是1了

$a=9
$b=9   
$c=1


$foo['love'] = 1;

$bar  = &$foo['love'];

$tipi = $foo;//就认为它是引用了,此时is_ref_gc已为1,没有对$tipi['love']写时拷贝

$tipi['love'] = '2';

echo $foo['love'];

http://www.php-internals.com/book/?p=chapt06/06-06-copy-on-write


foreach怪问题:

问题1:

复制代码代码如下:

$arr = array(1,2,3);
foreach($arr as $k => &$v) {
    $v = $v * 2;
}
// now $arr is array(2, 4, 6)
foreach($arr as $k => $v) {
    echo "$k", " => ", "$v";
}

先从简单的开始,如果我们尝试运行上述代码,就会发现最后输出为0=>2  1=>4  2=>4 。
为何不是0=>2  1=>4  2=>6 ?
其实,我们可以认为 foreach($arr as $k => $v) 结构隐含了如下操作,分别将数组当前的'键'和当前的'值'赋给变量$k和$v。具体展开形如:
复制代码代码如下:

foreach($arr as $k => $v){ 
    //在用户代码执行之前隐含了2个赋值操作
    $v = currentVal(); 
    $k = currentKey();
    //继续运行用户代码
    ……
}

根据上述理论,现在我们重新来分析下第一个foreach:
第1遍循环,由于$v是一个引用,因此$v = &$arr[0],$v=$v*2相当于$arr[0]*2,因此$arr变成2,2,3
第2遍循环,$v = &$arr[1],$arr变成2,4,3
第3遍循环,$v = &$arr[2],$arr变成2,4,6
随后代码进入了第二个foreach:
第1遍循环,隐含操作$v=$arr[0]被触发,由于此时$v仍然是$arr[2]的引用,即相当于$arr[2]=$arr[0],$arr变成2,4,2
第2遍循环,$v=$arr[1],即$arr[2]=$arr[1],$arr变成2,4,4
第3遍循环,$v=$arr[2],即$arr[2]=$arr[2],$arr变成2,4,4


详细:http://www.jb51.net/article/39299.htm



数组:

说明:一般的,数组的curd和sort全是操作数组本身,指针也是。

补充一点,就是curd(array,value)而search是(value,array)


//array排序6(sort r k u nat a )  str网络4(url header cookie session) file参数2(stat  pathinfo)

//array    元素 集合  kv  array_重组  回调 填充 计算  +排序
array() each()  reset()  end() array_pop() array_push() reset()  count() shuffle()  range() array_shift array_unshift current pos next prev 

array_multisort()   +排序 sort-升序 r-降序 k-键名+ a-保持索引关系 u-自定义算法 |nat-自然

array_intersect()  array_diff() 

array_unique()  array_chunk()  array_reverse()  array_flip() array_slice()  array_combine()  array_merge  array_rand  array_search

in_array()  array_keys() array_values()  array_key_exists()  list()  each() 
  
  array_filter()  array_walk()  array_map()

  array_sum array_product array_count_values   

  array_fill array_pad 

    

   //str 编码 转码 输出 分割 定位 正则 数学 变量  + 网络 
    trim strip_tags substr  parse_str  ord strrev strtoupper()  strtolower()  ucfirst() ucwords()  strcmp()  addslashes() stripslashes()  html_entity_decode() htmlspecialchars() htmlentities() htmlspecialchars_decode() 

    md5() sha1() base64_encode()  base64_decode()  urlencode()  urldecode()  http_build_url  stream_context_create()  

  echo print printf()  var_dump()

  strstr() strpos() stripos()  strrpos()  stristr()   

  preg_replace()  preg_match()  preg_match_all()   preg_grep  preg_split

  explode()  implode()  strlen()  str_replace()

  round()  floor() ceil() abs()   max  min  mt_rand

  empty() isset()  is_scalar()  

  setcookie() unset()  session_destroy()  header()  session_name  session_id  session_start  gethostbyaddr gethostbyname mail
 
    +date ( w d z + Y m d H i s)

  //文件  文件 目录 读写 上传 +参数

    fopen(a w a+ w+) fclose()  fclose()

    is_   is_uploaded_file()  move_uploaded_file()
 
    file_put_contents()  file_get_contents()  file_exists()  file  unlink rename flock  feof  fwrite fread  fgets

    dir() opendir() closedir()  mkdir  rmdir readdir

    stat (size atime mtime ctime )  pathinfo(dirname basename extension filename) 

===================================================1.0===================================================

net work: gethostbyaddr  gethostbyname  


stream:stream_context_create


url:urlencode urldecode http_build_query  parse_url


http:header 


dir:dir opendir closedir


file:fopen(r w a   +是读写方式打开  w和a都是写入,w是删除后写入,a是追加在末尾)  stat pathinfo  file_get/put_contents


math:ceil floor round mt_rand


hash:hash


session:id name path expire cookie | session_start/destroy/unset | session_set_save_handler   


setcookie(name,value,expire,path,domain,https) ==>add del session | session_destroy


date:date(J 日 N星期 W周 L闰年) getdate checkdate strtotime


variable:empty isset is_numeric/scalar


array:

1、元素 shift pop push end reset count

2、集合 intersect diff

3、排序 array_multisort  sort

4、搜索 array_search  array_keys in_array

5、创建 array  array_keys/values  array_merge array_flip array_list array_combine array_chunk array_slice

6、kv  each unique array_reverse

7、array_filter array_walk array_map


string:

1、转换 strtolower strtoupper ucfirst ucwords  html_entities/specials  strip/add_slashes  trim 

2、编码 ord md5 sha1

3、输出 echo printf

4、分割 explode implode str_splice/replace substr  strlen strcmp

5、搜索 str i(大小写)r(最后一个) pos(第一个)/str(末尾)

6、preg  preg_grep/match/replace/split


php:

排序冒泡 插入 快排 选择 |  

变量与引用只有变量才可以有地址,UNSET()删除时,只删除引用关系;如果重新给一个变量新的引用,引用关系发生改变;php中引用采用的是“写时拷贝”的原理,$a=$b=1 两个变量指向同一个内存地址,$a=$b=2 但重新赋值就会新申请内存

垃圾回收refcount__gc 表示引用计数 1   is_ref__gc 表示是否为引用 0   value 存储变量的值    type 变量具体的类型  unset() 并不会直接销毁变量 只有当refcount=0时才会被PHP的垃圾回收机制回收



0 0