首页 > 编程技术 > php

深入分析PHP运算符优先级

发布时间:2016-11-25 14:59

刚看PHP手册中 Boolean 布尔类型 数据类型时,看到了评论中一个关于运算符优先级的问题,以前也讲过在实际项目中不要出现这些需要人为判断运算符优先级的代码,都应该使用括号来规避这个问题的出现

周五一朋友来着一段代码来问我,说他看不懂这段代码,觉得这段代码有问题,代码类似:

 代码如下 复制代码

$array1 = array(1, 2);
$array2 = array(3, 4);

$result = empty($array1) == 3 ? $array1 : $array2;

我一看应该是运算符优先级的问题。
按理说,这些运算符优先级的问题是不应该让它出现在项目代码中的,只能让它在面试问题中,程序员应该在书写代码过程中使用括号来避免这种不确定问题的出现。项目中的代码应该是那种我们一看就知道结果的,而不是需要我们费劲脑子才能知道结果的。这种优先级代码的结果有时候并不是我们相信的那样,看看下面的例子:

 代码如下 复制代码

<?php
if ($a = 100 && $b = 200) {
     var_dump($a, $b);
}

上面代码也许你会认为是:

 代码如下 复制代码
<?php
if ($a = (100 && $b) = 200) {
     var_dump($a, $b);
}

但是实际上不是这样的,实际结果是:

 代码如下 复制代码
<?php
if ($a = (100 && $b = 200)) {
     var_dump($a, $b);
}

至于为什么会这样?那是因为PHP并不完全遵守优先级的定义,PHP手册上中有说明

Note: Although = has a lower precedence than most other operators, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.

代码:

代码1:

 代码如下 复制代码

<?php
$x=TRUE;
$y=FALSE;
$z=$y OR $x; ?>
代码2:
<?php
$x=TRUE;
$y=FALSE;
$z=$y || $x;
?>

这种代码在实际项目中是不应该出现的,都应该用下面的代码替换:

 代码如下 复制代码

$z = ($y OR $x);

$z = ($y || $x);

这是最简单的类型。 boolean 表达了真值,可以为 TRUE 或 FALSE ,布尔类型也是我们开发中常碰到的功能,下面我就来给各位同学整理一下它的用法。

语法:

要指定一个布尔值,使用关键字 TRUE 或 FALSE 。两个都不区分大小写。 

 

 代码如下 复制代码
<?php
$foo  =  True ;  // assign the value TRUE to $foo
?>

通常运算符所返回的 boolean 值结果会被传递给控制流程。 

 代码如下 复制代码

<?php
// == 是一个操作符,它检测两个变量是否相等,并返回一个布尔值
if ( $action  ==  "show_version" ) {
    echo  "The version is 1.23" ;
}

// 这样做是不必要的...
if ( $show_separators  ==  TRUE ) {
    echo  "<hr>n" ;
}

// ...因为可以使用下面这种简单的方式:
if ( $show_separators ) {
    echo  "<hr>n" ;
}
?>

转换为布尔值

要明确地将一个值转换成 boolean ,用 (bool) 或者 (boolean) 来强制转换。但是很多情况下不需要用强制转换,因为当运算符,函数或者流程控制结构需要一个 boolean 参数时,该值会被自动转换。 

当转换为 boolean 时,以下值被认为是 FALSE : 


1.布尔值 FALSE 本身
2.整型值 0(零)
3.浮点型值 0.0(零)
4.空字符串,以及字符串 "0"
5.不包括任何元素的数组
6.不包括任何成员变量的对象(仅 PHP 4.0 适用)
7.特殊类型 NULL(包括尚未赋值的变量)
8.从空标记生成的 SimpleXML 对象
所有其它值都被认为是 TRUE (包括任何资源)。

注意:1 和其它非零值(不论正负)一样,被认为是 TRUE ! 

 

 代码如下 复制代码
<?php
var_dump ((bool)  "" );         // bool(false)
var_dump ((bool)  1 );          // bool(true)
var_dump ((bool) - 2 );         // bool(true)
var_dump ((bool)  "foo" );      // bool(true)
var_dump ((bool)  2.3e5 );      // bool(true)
var_dump ((bool) array( 12 ));  // bool(true)
var_dump ((bool) array());    // bool(false)
var_dump ((bool)  "false" );    // bool(true)
?>
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。


单例模式的特点:

1、构造函数需要标记为private(访问控制:防止外部代码使用new操作符创建对象),单例类不能在其他类中实例化,只能被其自身实例化;

2、拥有一个保存类的实例的静态成员变量

3、拥有一个访问这个实例的公共的静态方法(常用getInstance()方法进行实例化单例类,通过instanceof操作符可以检测到类是否已经被实例化)

另外,需要创建__clone()方法防止对象被复制(克隆)

DEMO(链接数据库):

 代码如下 复制代码

/* 例子:数据库连接职责的集中控制 */
class Database {
 
private $_db;
static $_instance;
 
private function __construct() {
$this->_db = pg_connect('dbname=example_db');
}
 
private __clone() {};
 
public static function getInstance() {
 if(! (self::$_instance instanceof self) )
 {
 self::$_instance = new self();
 }
 return self::$_instance;
 
}
 
public function query($sql) {
// 使用 $this->_db 执行一个查询
return pg_query($this->_db, $sql);
}
}

文章主要是一个站长在学习php过程中一些用到的函数与方法及对各种方法的理解与简单的实例,下面全部放出来希望对你学习php有帮助。

PHP使用header函数设置HTTP头的示例方法

 代码如下 复制代码

//定义编码
header( Content-Type:text/html;charset=utf-8 );
//Atom
header(Content-type: application/atom+xml);
//CSS
header(Content-type: text/css);
//Javascript
header(Content-type: text/javascript);
//JPEG Image
header(Content-type: image/jpeg);
//JSON
header(Content-type: application/json);
//PDF
header(Content-type: application/pdf);
//RSS
header(Content-Type: application/rss+xml; charset=ISO-8859-1);
//Text (Plain)
header(Content-type: text/plain);
//XML
header(Content-type: text/xml);
// ok
header(HTTP/1.1 200 OK);
//设置一个404头:
header(HTTP/1.1 404 Not Found);
//设置地址被永久的重定向
header(HTTP/1.1 301 Moved Permanently);
//转到一个新地址
header(Location: http://www.example.org/);
//文件延迟转向:
header(Refresh: 10; url=http://www.example.org/);
print You will be redirected in 10 seconds;
//当然,也可以使用html语法实现
// <meta http-equiv="refresh" content="10;http://www.example.org/ />
// override X-Powered-By: PHP:
header(X-Powered-By: PHP/4.4.0);
header(X-Powered-By: Brain/0.6b);
//文档语言
header(Content-language: en);
//告诉浏览器最后一次修改时间
$time = time() - 60; // or filemtime($fn), etc
header(Last-Modified: .gmdate(D, d M Y H:i:s, $time). GMT);
//告诉浏览器文档内容没有发生改变
header(HTTP/1.1 304 Not Modified);
//设置内容长度
header(Content-Length: 1234);
//设置为一个下载类型
header(Content-Type: application/octet-stream);
header(Content-Disposition: attachment; filename="example.zip");
header(Content-Transfer-Encoding: binary);
// load the file to send:
readfile(example.zip);
// 对当前文档禁用缓存
header(Cache-Control: no-cache, no-store, max-age=0, must-revalidate);
header(Expires: Mon, 26 Jul 1997 05:00:00 GMT); // Date in the past
header(Pragma: no-cache);
//设置内容类型:
header(Content-Type: text/html; charset=iso-8859-1);
header(Content-Type: text/html; charset=utf-8);
header(Content-Type: text/plain); //纯文本格式
header(Content-Type: image/jpeg); //JPG***
header(Content-Type: application/zip); // ZIP文件
header(Content-Type: application/pdf); // PDF文件
header(Content-Type: audio/mpeg); // 音频文件
header(Content-Type: application/x-shockw**e-flash); //Flash动画

//显示登陆对话框
header(HTTP/1.1 401 Unauthorized);
header(WWW-Authenticate: Basic realm="Top Secret");
print Text that will be displayed if the user hits cancel or ;
print enters wrong login data;

php中static静态变量的使用方法详解
php中的变量作用范围的另一个重要特性就是静态变量(static 变量)。静态变量仅在局部函数域中存在且只被初始化一次,当程序执行离开此作用域时,其值不会消失,会使用上次执行的结果。

编程实例:

 代码如下 复制代码
function test()
{
  static $aa = 0;
  return $aa++;
}
$aa = "1000";
echo $aa;
echo test();
echo test();
echo $aa;
 

本函数每调用test()都会输出 $aa的值并加一。
上文代码运行输出:

1000
0
1
1000
 静态变量也提供了一种处理递归函数的方法。递归函数是一种自己调用自己的方法。写递归函数时要小心,因为可能会无穷递归下去,没有出口.务必确保 有方法来中止递归。

一维数组按照元素或者键值分组变为二维数组
有时候查询数据库记录后会对数据库查询结果进行分组,即将一维数组变为二维数组,方便调用使用(通常是json)

 代码如下 复制代码

$arr = array(
    '0'=>array(
            'firmware'=>'f1',
            'version'=>'1',
        ),
    '1'=>array(
            'firmware'=>'f1',
            'version'=>'2',
        ),
    '2'=>array(
            'firmware'=>'f1',
            'version'=>'3',
        ),
    '3'=>array(
            'firmware'=>'f2',
            'version'=>'1',
        ),
    '4'=>array(
            'firmware'=>'f2',
            'version'=>'2',
        ),
    );
    $new_arr  =  array();
    foreach ($arr as $row ){
        $new_arr[$row['firmware']][] = $row['version'];
    }
    var_dump($new_arr);
转换后

Array
(
    [f1] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )

    [f2] => Array
        (
            [0] => 1
            [1] => 2
        )

)

PHP的静态绑定和动态绑定(private/public)
子类Foo的对象调用了test()方法,test()方法调用了$this->testPrivate();这个$this此时应该是子类的引用,按理说应该调用子类的testPrivate()方法,实际上却调用了父类的testPrivate()方法

 代码如下 复制代码

class Bar
{
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }

    public function testPublic() {
        echo "Bar::testPublicn";
    }
   
    private function testPrivate() {
        echo "Bar::testPrivaten";
    }
}

class Foo extends Bar
{
    public function testPublic() {
        echo "Foo::testPublicn";
    }
   
    private function testPrivate() {
        echo "Foo::testPrivaten";
    }
}

$myFoo = new Foo();
$myFoo->test();
// 运行结果
// Bar->testPrivate
// Foo->testPublic

这是PHP的动态绑定和静态绑定的一种情况。

public是动态绑定,在编译期不绑定,所以在运行期调用父类的test()方法的时候,会解析为子类的public方法。

而private是私有的,不会继承到子类,在编译期就绑定了,是一种“静态”的绑定(类似5.3后的self)。

与这个相关的是LSB,静态延迟绑定,PHP5.3因为有了这个特性之后,使PHP的OOP得到加强

public: 可以被继承,也可以被外部调用。

private: 不可以被继承,也不可以被外部调用。

protected: 可以被继承,但不能被外部调用。

PHP三种运行方式mod_php5/cgi/fast-cgi
a.通过HTTPServer内置的模块来实现,
例如Apache的mod_php5,类似的Apache内置的mod_perl可以对perl支持;

b.通过CGI来实现
这个就好比之前perl的CGI,该种方式的缺点是性能差,因为每次服务器遇到这些脚本都需要重新启动脚本解析器来执行脚本然后将结果返回给服务器;另一方面就是不太安全;该方面几乎很少使用了。

c.最新出现一种叫做FastCGI。
所谓FastCGI就是对CGI的改进。它一般采用C/S结构,一般脚本处理器会启动一个或者多个daemon进 程,每次HTTPServer遇到脚本的时候,直接交付给FastCGI的进程来执行,然后将得到的结果(通常为html)返回给浏览器。

该种方法的问题存在一个小问题是当遇到大流量的频繁请求的话,脚本处理器的daemon进程可能会超负荷从而变得很慢,甚至发生内存泄漏;

但是比较起Apache的内置模块的方式的优点是由于Server和脚本解析器完全分开各负其责,因此服务器不再臃肿,可以专心地进行静态文件响 应或者将动态脚本解析器的结果返回给用户客户端。所以比较起Apache的内置模块方式,有时候性能要提高很多。有人测试可能会达到 Apache+mod_php的5~10倍。

三种常用模式:
Apache+mod_php5;

lightppd+spawn-fcgi;

nginx+PHP-FPM

我们可以使用到生产环境中的:
0) 如果不是server cluster的话:
可以使用以上任一种,不过有各种测试表明nginx+PHP-FPM性能优越,但是Apache+mod_php5很经典模块多,比如对.htaccess等的支持。

如果构建server cluster的话:
1) nginx作为反向代理服务器,后台多台Apache+mod_php5。
nginx处理静态文件,及对php并发请求对后台多台app server的负载均衡;

2) nginx作为反向代理器,后台多台PHP-FPM
nginx处理静态文件及将php并发请求发送到后台php-fpm来解析;

三种变量命名规则(匈牙利法,小驼峰法,大驼峰法)
1. 匈牙利命名:
•开头字母用变量类型的缩写,其余部分用变量的英文或英文的缩写,要求单词第一个字母大写。
•For example: long lsum = 0;"l"是类型的缩写;
2. 小驼峰式:(little camel-case)
•第一个单词首字母小写,后面其他单词首字母大写。
•For example: string firstName = string.Empty;
3. 大驼峰式:(big camel-case)
•每个单词的第一个字母都大写;
•For example:string FirstName = string.Empty;
解决 Json 中文转码问题

 代码如下 复制代码
//代码
$data = array(
    'status'=>'1',
    'method'=>'登陆',
    'message'=>'成功',
);
echo json_encode($data);
//显示
{"status":"1","method":"u767bu9646","message":"u6210u529f"}

json_encode 只能接受utf-8格式的数据,最终的json中中文部分被替换为unicode编码。我们要解决的就是将对象转换为json并保证对象内部的中文在json中仍然是以正常的中文出现。

先将类中的中文字段进行url编码(urlencode),然后再对对象进行json编码(jsonencode),最后url解码(urldecode)json,即最终的json,里面的中文依旧是那个中文。

 代码如下 复制代码
//代码
foreach ( $data as $key => $value ) {
    $newData[$key] = urlencode ( $value );
}
echo urldecode(json_encode($newData));
//显示
{"status":"1","method":"登陆","message":"成功"}

Ajax跨域请求CORS错误
编写Json api供其他站点查询调用的时候有时候使用ajax方式获取,此时,可能ACAO的设置,那么将发生CROS错误。

//报错
XMLHttpRequest cannot load http://www.111cn.net . No 'Access-Control-Allow-Origin' header is present on the requested resource.
//解决办法

 代码如下 复制代码

header('Access-Control-Allow-Origin: *'); 
header('Access-Control-Allow-Origin: ccdd.com');
codeigniter指定地址实现HTTPS访问管理
//启动hooks
//app/config/config.php
$config['enable_hooks'] = TRUE;

//hooks配置
///app/config/hooks.php
$hook['post_controller_constructor'][] = array(
        'function' => 'check_ssl',
        'filename' => 'ssl.php',
        'filepath' => 'hooks',
    );

//插件编写
//app/hooks/ssl.php
function check_ssl(){
$CI =& get_instance();
$class = $CI->router->fetch_class();
$method = $CI->router->fetch_method();


$ssl = $CI->config->item('ssl_class_method');  
$partial = $CI->config->item('no_ssl_class_method');   

if(in_array($class.'/'.$method,$ssl)){
    //force_ssl();
    $CI =&get_instance();
    $CI->config->config['base_url'] = str_replace('http://', 'https://', $CI->config->config['base_url']);
    if ($_SERVER['SERVER_PORT'] != 443) redirect($CI->uri->uri_string());
}
else if(in_array($class.'/'.$method,$partial))
{
        return;
    }
    else{
        //unforce_ssl
        $CI =&get_instance();
        $CI->config->config['base_url'] = str_replace('https://', 'http://', $CI->config->config['base_url']);
        if ($_SERVER['SERVER_PORT'] == 443) redirect($CI->uri->uri_string());
    }
}

//config 配置需要使用https的 class method
//app/config/config.php
$config['ssl_class_method'] = array(
    'U_class/A_method',
    'V_class/B_method',
    'W_class/C_method',
    'X_class/D_method',
    ); //强制使用ssl
$config['no_ssl_class_method'] = array();

//强制不使用ssl

最简单的全局变量函数就是$_SERVER[\'DOCUMENT_ROOT\']与$HTTP_SERVER_VARS[\'DOCUMENT_ROOT\']了,但是我们要调用文件的话就无法这样实现了,具体如何写呢,下面我们一起来看看。

用php开发网站的时候有时候经常要用到当前网站的根目录, 比如包含一个文件:

 代码如下 复制代码

include_once("./includefile.php");

那么要想写根目录的形式应该怎么写呢?

这时候通常用 dirname(__FILE__) 这个函数, 意思是获取当前文件所在的根目录, 

那么这个php语句就是这样的了:

 代码如下 复制代码

include_once(dirname(__FILE__) ."/includefile.php");


将下面的代码放在网站根目录下的一个文件中,以便在其它文件中引用。

路径方式:

 代码如下 复制代码

define('BASE_PATH',str_replace('\\','/',realpath(dirname(__FILE__).'/'))."/");

echo BASE_PATH;


输出结果:E:/www.111cn.net /

url方式:

 代码如下 复制代码

 

$PHP_SELF=$_SERVER['PHP_SELF'];

$url='http://'.$_SERVER['HTTP_HOST'].substr($PHP_SELF,0,strrpos($PHP_SELF,'/')+1);

echo $url;


//注意大小写问题, linux下对大小写敏感, 要养成认真对待大小写的习惯, 以免win主机换到linux下不兼容的问题

标签:[!--infotagslink--]

您可能感兴趣的文章: