xml中的<![CDATA[]]>和转义字符

<![CDATA[]]>这个标记所包含的内容将表示为纯文本,比如<![CDATA[<]]>表示文本内容“<”
此标记用于xml文档中,我们先来看看使用转义符的情况。我们知道,在xml中,”<””>””&”等字符是不能直接存入的,否则xml语法检查时会报错,如果想在xml中使用这些符号,必须将其转义为实体,如”&lt;””&gt;””&amp;”,这样才能保存进xml文档。
在使用程序读取的时候,解析器会自动将这些实体转换回”<””>””&”。举个例子:
<age> age < 30 </age>
上面这种写法会报错,应该这样写:
<age> age &lt; 30 </age>
值得注意的是:
(1)转义序列字符之间不能有空格;
(2) 转义序列必须以”;”结束;
(3) 单独出现的”&”不会被认为是转义的开始;
(4) 区分大小写。在XML中,需要转义的字符有:
(1)&   &amp; 
  (2)<   &lt; 
(3)>   &gt;
(4)"   &quot;
(5)'   &apos;
但是严格来说,在XML中只有”<”和”&”是非法的,其它三个都是可以合法存在的,但是,把它们都进行转义是一个好的习惯。
不管怎么样,转义前的字符也好,转义后的字符也好,都会被xml解析器解析,为了方便起见,使用<![CDATA[]]>来包含不被xml解析器解析的内容。但要注意的是:
(1) 此部分不能再包含”]]>”
(2) 不允许嵌套使用;
(3)”]]>”这部分不能包含空格或者换行。
最后,说说<![CDATA[]]>和xml转移字符的关系,它们两个看起来是不是感觉功能重复了?
是的,它们的功能就是一样的,只是应用场景和需求有些不同:
(1)<![CDATA[]]>不能适用所有情况,转义字符可以;
(2) 对于短字符串<![CDATA[]]>写起来啰嗦,对于长字符串转义字符写起来可读性差;
(3) <![CDATA[]]>表示xml解析器忽略解析,所以更快。

用PHP5的SimpleXML解析XML文档

www.xuduowei.com/archives/91

 

为什么要使用PHP单例模式及应用实例

首先我们要知道明确单例模式这个概念,那么什么是单例模式呢?

单例模式顾名思义,就是只有一个实例。

作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,

这个类我们称之为单例类。

单例模式的要点有三个:

一是某个类只能有一个实例;

二是它必须自行创建这个实例;

三是它必须自行向整个系统提供这个实例。

下面我们讨论下为什么要使用PHP单例模式?

多数人都是从单例模式的字面上的意思来理解它的用途, 认为这是对系统资源的节省, 可以避免重复实例化, 是一种”计划生育”。而PHP每次执行完页面都是会从内存中清理掉所有的资源. 因而PHP中的单例实际每次运行都是需要重新实例化的, 这样就失去了单例重复实例化的意义了. 单单从这个方面来说, PHP的单例的确有点让各位失望. 但是单例仅仅只有这个功能和应用吗? 答案是否定的,我们一起来看看。

1. php的应用主要在于数据库应用, 所以一个应用中会存在大量的数据库操作, 在使用面向对象的方式开发时(废话), 如果使用单例模式, 则可以避免大量的new 操作消耗的资源。

2. 如果系统中需要有一个类来全局控制某些配置信息, 那么使用单例模式可以很方便的实现. 这个可以参看zend framework的FrontController部分。

3. 在一次页面请求中, 便于进行调试, 因为所有的代码(例如数据库操作类db)都集中在一个类中, 我们可以在类中设置钩子, 输出日志,从而避免到处var_dump, echo。

* 单例模式举例,其要点如下:
*
* 1. $_instance 必须声明为静态的私有变量
* 2. 构造函数和克隆函数必须声明为私有的,这是为了防止外部程序new 类从而失去单例模式的意义
* 3. getInstance()方法必须声明为公有的,必须调用此方法以返回唯一实例的一个引用
* 4. ::操作符只能访问静态变量或静态函数
* 5. PHP的单例模式是相对而言的,因为PHP的解释运行机制使得每个PHP页面被解释执行后,所有的相关资源都会被回收。
* 也就是说,PHP在语言级别上没有办法让某个对象常驻内存。在PHP中,所有的变量都是页面级的,无论是全局变量, 还是类的静态成员,都会在页面执行完毕后被清空,结果会重新建立新的对象,这样也就完全失去了Singleton的意义。
* 不过,在实际应用中同一个页面中可能会存在多个业务逻辑,这时单例模式就起到了很重要的作用,有效的避免了重复  new 对象(注: new 对象会消耗内存资源)这么一个行为,所以我们说PHP的单例模式是相对而言的。

数组排序问题:

js:

<script>
var a=Array(1,2,3,100,200,60,50); 

a.sort(function(a,b){
	if(a<b){return 1 //a<b return 1从大到小的排序
	} else{
	return 0
	}
})

alert(a);
</script>

PHP:方法一:

<?php
 $a=array(1,2,3,100,200,60,50);

 usort($a,function($a,$b){
	if($a<$b){
		return 1; //a<b return 1从大到小的排序
	} else{
	return 0;
	}
});
  print_r($a);

?>

PHP方法二:

<?php
 $a=array(1,2,3,100,200,60,50);
rsort($a);//rsort从大到小排序  ;sort是从小到大
 
  print_r($a);

?>

 

 

 

2个自定义的PHP in_array 函数,解决大量数据判断in_array的效率问题

大家可能都用过in_array来判断一个数据是否在一个数组中,一般我们的数组可能数据都比较小,对性能没什么影响,所以也就不会太在意。

但是如果数组比较大的时候,性能就会下降,运行的就会久一点,那如果针对在大数组情况下做优化呢,下面说两种方法(都是通过自定义函数来实现):

1.数组key与value翻转,通过isset判断key是否存在于数组中

/**
 * in_array is too slow when array is large
 */
function inArray($item, $array) {
    $flipArray = array_flip($array);
    return isset($flipArray[$item]);
}

大家可能也会问为什么不用 array_key_exists 来做判断二用isset呢? 下面看下array_key_exists() 与 isset() 的对比:
isset()对于数组中为NULL的值不会返回TRUE,而array_key_exists()会。

<?php
$search_array = array('first' => null, 'second' => 4);
// returns false
isset($search_array['first']);
// returns true
array_key_exists('first', $search_array);
?>

2.用implode连接,直接用strpos判断

用implode函数+逗号连起来,直接用strpos判断。php里面字符串取位置速度非常快,尤其是在大数据量的情况下。不过需要注意的是首尾都要加”,” ,这样比较严谨。如: ,user1,user2,user3, 查找的时候,查,user1,。还有strpos要用!== false,因为第一个会返回0。示例如下:

return strpos($str,(string)$item)==false?false:true;**
 * in_array is too slow when array is large
 */
function inArray($item, $array) {
    $str = implode(',', $array);    
    return strpos($str,(string)$item)==false?false:true;
}

提示:以上2个函数均有bug!方法一数组翻转中,若原始数组值有null的,是会出问题的;方法二的只能验证字符串类型的。无法验证整形数字。总结:还是in_array($str,$arr,true) 验证方式最安全可靠。虽然性能相对底一点。

 

 

 

php自带的sort排序和用php实现排序算法的性能比较?

我今天特地试验了一下两者的性能
php自带的排序函数 100000的数据 排序 平均耗时0.068s
microtime() //php自带排序sort()耗时:0.12000608444214 
返回当前 Unix 时间戳的微秒数。
 for ($i = 0; $i<100000;$i++){

    $arr[] = rand(0,10000);
}

 $t1 = microtime(true);

sort($arr);

$t2 = microtime(true);
echo "php自带排序sort()耗时:".($t2-$t1); 

自己写的快速排序 平均耗时1.0s

//快速排序耗时:1.7631008625031

 for ($i = 0; $i<100000;$i++){

    $arr[] = rand(0,100000);
}

 $t1 = microtime(true);

$returnAr = quickSort($arr);

$t2 = microtime(true);
echo "快速排序耗时:".($t2-$t1); 
//快速排序
function quickSort($arr) {
    //先判断是否需要继续进行
    $length = count($arr);
    if($length <= 1) {
        return $arr;
    }
    //选择第一个元素作为基准
    $base_num = $arr[0];
    //遍历除了标尺外的所有元素,按照大小关系放入两个数组内
    //初始化两个数组
    $left_array = array();  //小于基准的
    $right_array = array();  //大于基准的
    for($i=1; $i<$length; $i++) {
        if($base_num > $arr[$i]) {
            //放入左边数组
            $left_array[] = $arr[$i];
        } else {
            //放入右边
            $right_array[] = $arr[$i];
        }
    }
    //再分别对左边和右边的数组进行相同的排序处理方式递归调用这个函数
    $left_array = quickSort($left_array);
    $right_array = quickSort($right_array);
    //合并
    return array_merge($left_array, array($base_num), $right_array);
}

明显是php自带的函数排序速度快很多。
但重点是,为什么还有那么多问题是问 如何用php实现快速排序等算法?

php四排序-冒泡排序

算法和数据结构是一个编程工作人员的内功,技术牛不牛,一般都会看这两点。作为php程序员, 提升技能当然也得学习算法。

下面介绍四种入门级排序算法: 冒泡排序、选择排序、插入排序、快速排序。

一、冒泡排序

原理:对一组数据,比较相邻数据的大小,将值小数据在前面,值大的数据放在后面。   (以下都是升序排列,即从小到大排列)

举例说明: $arr = array(6, 3, 8, 2, 9, 1);

$arr 有6个数据,按照两两比较大小如下,注意  比较轮数 和 每轮比较次数

 第一轮排序:

第一次比较  6和3比较 结果:3    6   8   2   9   1

第二次比较  6和8比较 结果:3    6   8   2   9   1

第三次比较  8和2比较 结果:3    6   2   8   9   1

第四次比较  8和9比较 结果:3    6   2   8   9   1

第五次比较  9和1比较 结果:3    6   2   8   1   9

第一轮比较总结:1.排序第1轮、比较5次,没有获得从小到大的排序   2.因为每次比较都是大数往后靠,所以比较完成后,可以确定大数排在最后(9 已经冒泡冒出来了,下轮比较可以不用比较了 )

第二轮排序:

第一次比较  3和6比较 结果:3    6   2   8   1   9

第二次比较  6和2比较 结果:3    2   6   8   1   9

第三次比较  6和8比较 结果:3    2   6   8   1   9

第四次比较  8和1比较 结果:3    2   6   1   8   9

第二轮比较总结:1.排序第2轮、比较4次,没有获得从小到大的排序   2.冒泡出了 8,下轮不用比较8 了

第三轮排序:

第一次比较  3和2比较 结果:2    3   6   1   8   9

第二次比较  3和6比较 结果:2    3   6   1   8   9

第三次比较  6和1比较 结果:2    3   1   6   8   9

第三轮比较总结:1.排序第3轮、比较3次,没有获得从小到大的排序   2.冒泡出了 6,下轮不用比较6 了

  第四轮排序:

第一次比较  2和3比较 结果:2    3   1   6   8   9

第二次比较  3和1比较 结果:2    1   3   6   8   9

第四轮比较总结:1.排序第4轮、比较2次,没有获得从小到大的排序   2.冒泡出了 3,下轮不用比较3 了

  第五轮排序:

第一次比较  2和1比较 结果:1   2   3   6   8   9

第五轮比较总结:1.排序第5轮、比较1次,没有获得从小到大的排序   2.冒泡出了 2,由于还剩一个1,不用再比较了,至此通过5轮排序,完成整个排序。

  通过以上五轮排序,若干次比较,我们有理由推断出一个结论:

  对于一个长度为N的数组,我们需要排序 N-1 轮,每 i 轮 要比较 N-i 次。对此我们可以用双重循环语句,外层循环控制循环轮次,内层循环控制每轮的比较次数。

<?php 

function getpao($arr)
{ 
 $len=count($arr);
 //设置一个空数组 用来接收冒出来的泡
 //该层循环控制 需要冒泡的轮数
 for($i=1;$i<$len;$i++)
 { //该层循环用来控制每轮 冒出一个数 需要比较的次数
 for($k=0;$k<$len-$i;$k++)
 {
 if($arr[$k]>$arr[$k+1])
 {
 $tmp=$arr[$k+1];
 $arr[$k+1]=$arr[$k];
 $arr[$k]=$tmp;
 }
 }
 }
 return $arr;
}


 $arr= array(6,3,8,2,9,1);
$res =  getpao($arr);
print_r($res);

 

thinkphp5中.htaccess 的定义,通过这个模式,也适用于其他.htaccess定义

<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On

#index.php/admin/users/index.html
RewriteRule ^(.*)list\.html$ $1/admin/users/index\.html

#index.php/admin/users/update/id/1.html
RewriteRule ^(.*)show_([0-9]+)\.html$ $1/admin/users/update/id/$2

#index.php/admin/users/index.html?page=2
RewriteRule ^(.*)p_([0-9]+)\.html$ $1/admin/users/index/page/$2
# http://127.0.0.1/tc/004_oop/tp5/public/p_2.html

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

tp5分页效果,中间数字化的设置。

核心分页默认文件的路径:tp5\thinkphp\library\think\paginator\driver\Bootstrap.php

 /**
     * 页码按钮
     * @return string
     */
	 /*
    protected function getLinks()
    {
}

这个函数是我们要修改替换的!

我这里推荐一个:http://www.thinkphp.cn/code/3000.html

 public $rollPage=1;//侧面显示个数
protected function getLinks()
 {
 if ($this->simple)
 return '';
 
 $block = [
 'first' => null,
 'slider' => null,
 'last' => null
 ];
 
 $side = $this->rollPage;
 $window = $side * 2;
 
 if ($this->lastPage < $window +1) {
 $block['slider'] = $this->getUrlRange(1, $this->lastPage);
 
 } elseif ($this->currentPage <= $window-1) {
 
 $block['slider'] = $this->getUrlRange(1, $window + 1);
 } elseif ($this->currentPage > ($this->lastPage - $window+1)) {
 $block['slider'] = $this->getUrlRange($this->lastPage - ($window), $this->lastPage);
 
 } else {
 
 $block['slider'] = $this->getUrlRange($this->currentPage - $side, $this->currentPage + $side);
 }
 
 $html = '';
 
 if (is_array($block['first'])) {
 $html .= $this->getUrlLinks($block['first']);
 }
 
 if (is_array($block['slider'])) {
 
 $html .= $this->getUrlLinks($block['slider']);
 }
 
 if (is_array($block['last'])) {
 $html .= $this->getUrlLinks($block['last']);
 }
 
 return $html;
 }

控制器中如何智能化设置呢?注意上面的:public $rollPage=1;//侧面显示个数

我们在控制器中的引用是这样的:

$list=$obj->where($tj)->paginate(2,false, [
                ‘query’ => Request::instance()->param(),//不丢失已存在的url参数
            ]);
$list->rollPage=2;//一定要放在$list->paginate 之后哦。这里就是重新对分页栏每页显示的页数进行定义了。

tp5分页效果 上一篇,下一篇的自定义修改。

核心分页默认文件的路径:tp5\thinkphp\library\think\paginator\driver\Bootstrap.php

对应的上一个方法名:

 /**
     * 上一页按钮
     * @param string $text
     * @return string
     */
    protected function getPreviousButton($text = "&laquo;")
    {

}

 /**
 * 下一页按钮
 * @param string $text
 * @return string
 */
 protected function getNextButton($text = '&raquo;')
 {
详细略
}

提示:你可以直接设置$text="默认值为上一篇/下一篇",但是这样就写死了,我们希望通过视图的方式直接修改上一篇或者下一篇的具体内容。
视图代码:	
{$list->render("上一个","下一个")} ;//注意,默认这样传值是不对的,我们还需要按如下流程操作。
在tp5\thinkphp\library\think\paginator\driver\Bootstrap.php 文件中
搜索: public function render()
修改:
 public function render($a="",$b="")
 {
 if ($this->hasPages()) {
 if ($this->simple) {
 return sprintf(
 '<ul class="pager">%s %s</ul>',
 $this->getPreviousButton($a),
 $this->getNextButton($b)
 );
 } else {
 return sprintf(
 '<ul class="pagination">%s %s %s</ul>',
 $this->getPreviousButton($a),
 $this->getLinks(),
 $this->getNextButton($b)
 );
 }
 }
 }