分类 php 下的文章

最近在试着做一个问答系统,有个需求是记录用户的各种活动(activities)作为站点动态,传统的实现方式需要写大量重复的代码,而且可能会给后期版本迭代增加难度,为了改善这种情况,可以使用简单的观察者模式。
下面是一个简单的观察者模式示例,它实现了用户在发布问题时,通知EventLog,记录下用户的操作:

<?php

class QuestionActions{
    
    /**
     * 内部属性用来存放观察者对象
     */
    protected $_observer = null;

    /**
     * 传入观察者对象
     */
    public function notifyObserver($observer){
        $this->_observer = $observer;
    }

    /**
     * 调用观察者记录事件
     */
    public function putQuestion($user,$question){
        $this->_observer->writeLog($user,$question);
    }


}

/**
 * 定义时间记录类
 */
class EventsLog{

    public function writeLog($user,$question){
        echo "- <small><b>".$user."</b> 新增了问题:<b>“ ".$question."”</b></small><br/>";
    } 

}

$action = new QuestionActions();
$action->notifyObserver(new EventsLog());
$action->putQuestion('猪八戒','猴哥,咱们什么时候开饭啊?');

$action = new QuestionActions();
$action->notifyObserver(new EventsLog());
$action->putQuestion('沙和尚','师傅去哪了?');

$action = new QuestionActions();
$action->notifyObserver(new EventsLog());
$action->putQuestion('孙悟空','妖怪哪里逃?');

效果图:

QQ图片20200428180804.png

2019年11月,豆瓣API停止服务,下列插件已经无法使用,停止维护!

花了两个晚上的时间,写了一个小插件,用于在文章中引用豆瓣图书的时候可以嵌入豆瓣图书的信息,实现原理也很简单,无非就是正则匹配然后替换返回。
下面是实际的使用效果:
在博文中输入了[book:1441789]会自动生成如下的图书信息卡片。
[book:1441789]

使用方法也非常的简单,上传到插件目录激活后即可,在撰写文章或者页面时输入[book:图书编号]即可。
为了防止调用过于频繁被豆瓣屏蔽,首次调用豆瓣图书API后,获取到的json信息和图书封面文件都会保存在本地。

usr/plugins/BookInfo/resources/bookinfo 这里存放了以图书编号命名的json数据;
usr/plugins/BookInfo/resources/bookcover 这里存放了以图书编号命名的封面图片;

删除上述文件夹下的内容并不影响使用,插件会重新获取对应的图书信息。

下载地址:

Github

本站

<?php

// 字符串的使用细节


/**
 *  一 单引号的使用
 *  效率高,不对变量进行解析
 */


$num =10;
$str = 'hello beijing $num';
echo '<pre>';
var_dump($str);
echo $str.'<hr />';


/**
 * 二 双引号的使用
 * 双引号会对$解析,效率低
 */



$num =10;
$str = "hello beijing $num";
echo '<pre>';
var_dump($str);
echo $str.'<hr />';

// 在双引号中解析数组元素等复杂变量时,应当加上{}

$arr = array(
    'one'=>'cat',
    'two'=>'mouse',
    'three'=>'pig'
);

echo "数组键直为one对应的值为{$arr['one']}<hr />";


/**
 * heredoc的使用
 * 定界符可以自定义,一般大写,以 <<<定界符 换行后添加内容,定界符需一致
 * heredoc 用于输出大段的HTML代码,会解析变量
 */

 $str = '强大的';
 $div = <<<HTMLCON

 <div>
    <h2>Wow! {$str}heredoc</h2>
    <ul>
        <li>first</li>
        <li>second</li>
        <li>third</li>
    </ul>
 </div>
HTMLCON;


echo $div.'<hr />';


/**
 * nowdoc的使用
 * heredoc的开始定界符加上单引号,区别是nowdoc不解析变量
 * 
 */


$div = <<<'HTMLCON'

<div>
   <h2>Wow! {$str}heredoc</h2>
   <ul>
       <li>first</li>
       <li>second</li>
       <li>third</li>
   </ul>
</div>
HTMLCON;

echo $div;

正则表达式

英文: regular expression , 用来匹配符合某些规则的字符串,但比wildcard通配符更为高级,功能也更强大。

元字符

英文: metacharacter, 在正则表达式中含有特殊的意义。

/b : 用来表示开头和结尾
* : 用来表示任何不包含换行符的内容

在过去,如果我们想要实现某个类文件的自动加载,可以使用__autoload()魔术方法。紧接着,随着PHP的不断发展,我们可以通过使用spl_autoload_register()来注册自己定义的自动加载方法,PHP5.3之后,我们可以通过使用命名空间的方法来有效的解决类和方法的重名问题。

实现类库文件的自动加载,在很大程度上提升了代码的质量,以下篇幅记录了如何借助命名空间实现类库文件的自动加载。

- 阅读剩余部分 -

经常在许多框架中看到直接使用了数组作为写入数据或者查询数据库的参数,形如insert($_POST=array('content'=>'Hello World!','author_id'=>3));或者 fetch(array('status'=>'public','type'=>'post')); 这样的调用方法,如何实现数组数据中的键和值分别作为SQL语句中的列和value呢?其实非常简单:

- 阅读剩余部分 -

最终还是放弃了ThinkPHP,投向codeIgniter的怀抱,虽然说现在最有逼格的框架是Laravel,可是在连续两次使用Composer创建项目失败,并且看到vendor目录下令人作呕的文件目录结构以后,我想我这辈子可能都不会再想去碰Laravel了。好了,不吐嘈了。
下面是Ubuntu14.04下配置Apache2.4.7实现伪静态的过程:


- 阅读剩余部分 -

概念:
抽象方法:类中有一个方法,而方法并没有方法体,这种方法叫作抽象方法
抽象类:只要包含抽象方法的类一定就是抽象类,而抽象类中不一定包含抽象方法,抽象类中可以同时包含普通方法和抽象方法。



- 阅读剩余部分 -

将对象或者数组串行化后,可以写入数据库中。
这是一个串行后的数组:

string(172) "a:5:{s:4:"name";s:25:"201712261823302368352.gif";s:4:"path";s:35:"/usr/uploads/2018/01/3072538610.gif";s:4:"size";i:526047;s:4:"type";s:3:"gif";s:4:"mime";s:9:"image/png";}"

转换成数组

将数组串行化成文本:

$string = serialize($array);

将串行文本转换成数组

$array = unserialize($string);

<?php

echo "OK";

// phpinfo();
//取得指定位址的內容,並儲存至text  
$text=file_get_contents('https://www.yidaiyilu.gov.cn/info/iList.jsp?cat_id=10360');  

$text=str_replace(array("\r","\n","\t","\s"), '', $text); 
// var_dump($text);
//取出div標籤且id為PostContent的內容,並儲存至陣列match  


preg_match('/<div[^>]*class="list_right left"[^>]*>(.*?) <\/div>/si',$text,$match);

preg_match('/<ul[^>]*class="commonList_dot"[^>]<li[^>]*>(.*?) <\/div>/si',$text,$match);

<ul class="commonList_dot"><li>
                                                   

preg_match('/<li[^>]*>/Ui', $match[0], $m);


  
//印出match  
//print_r($match);
/*
$length = count($match);
while ($i <= $length) {
 echo($match[$i]);
 $i++;
}

*/
?>

决定扔掉那些集成开发环境,今后的学习和开发均在vagrant+virtual+ubuntu下完成。vagrant的搭建可以说是非常快捷了,其原理就是将依赖环境搭建在虚拟机中,然后将本地文件(宿主机)映射到虚拟机并实现访问。即便如此,在搭建过程中依然有不少的坑要填。

安装vagrant 和 virtualbox

日常的工作和学习,我基本上都是在win7和MacOS下完成的,因此使用vagrant可以帮助我非常容易的实现在不同系统下部署完全一致的开发环境。
之所以在2017年的今天还在使用Ubuntu 14.04是因为这台Win7机器下只有低于Ubuntu14.04(含)的版本的Box盒子才能正常跑起来,主要是受vagrant版本太低的限制。
win7 下应当采用vagrant 1.9.3+ Virtualbox 5.1.3的组合,否则会出现各种像无法启动box,启动box后卡在密钥验证那里无法进入系统等奇葩问题,官方给出的解释是,win7最高支持到1.9.3。
Mac 10.12 下可以直接安装最新版,直接去官网下载最新的DMG安装包安装就好。

目录设置

 └─trusty32  
     ├─.vagrant
     │  └─machines
     │  └─default
     │  └─virtualbox
     └─www   # 共享目录,宿主机文件和虚拟机同步目录

Vagrantfile配置(分配IP和共享目录)

config.vm.network "private_network", ip: "192.168.33.20" 指定虚拟机IP为 192.168.33.20

config.vm.synced_folder "./www", "/vagrant/www/", :mount_options => ["dmode=777","fmode=777"] 分配共享目录,即trusty32下的www的目录挂载在虚拟机/vagrant/www目录下。

vagrant和virtualbox的安装非常简单,不再赘述。主要记录ubuntu 14.04下搭建PHP7+Mysql+Apache2.4+Adminer的过程:

安装Apache

更新镜像源:sudo apt-get update && sudo apt-get upgrade

安装Apache2.4: sudo apt-get install apache2。安装完成在浏览器输入192.168.33.20,看到Apache2 Ubuntu Default Page: It Works!则说明Apache2安装成功。

安装 Mysql

wget http://dev.mysql.com/get/mysql-apt-config_0.6.0-1_all.deb 下载MYSQL5.7安装包
sudo dpkg -i mysql-apt-config_0.6.0-1_all.deb 添加到库
sudo apt-get update 更新软件源
sudo apt-get install mysql-server 安装Mysql服务

安装过程中会要求输入root密码。

安装完成后输入 mysql -uroot -p登入Mysql服务器验证是否成功安装了mysql服务

安装PHP7.0

sudo apt-get install php7.0 php7.0-cli php7.0-fpm php7.0-gd php7.0-json php7.0-mysql php7.0-readline php7.0-xml php7.0-mbstring php7.0-curl

整合

整合PHP与Mysql

sudo apt-get install php7.0-mysql

整合PHP与Apache
sudo apt-get install libapache2-mod-php7.0
重启Apache sudo service apache2 restart

验证

在apache默认网页目录下新建info.php
sudo vi info.php

<?php
echo mysqli_connect('localhost','root','root')?"数据库连接成功":"数据库连接出错";
phpinfo();

/*
# 单例设计模式
*/


class multiObj{
    public function __construct(){
        echo " DataBase Linked <br />";
    }
    public function select(){
        echo "select *";
    }
}

$obj1 = new multiObj(); # 生成 Obj#1
$obj2 = new multiObj(); # 生成 Obj#2
$obj3 = new multiObj(); # 生成 Obj#3
var_dump($obj1);
var_dump($obj2);
var_dump($obj3);



/* 单例设计模式,可以防止类被多次的实例化 */

class singleObj{
        static $obj = null; # 用来标记实例,默认不存在
        private function __construct(){
            echo "<br />DataBase Linked<br/>";
        }
        static function getObj(){
            if(is_null(self::$obj)){  # 判断实例是否存在
               self::$obj = new self(); 
               #不存在则实例化类生成实例 , singleObj()换成self()
            }
             return self::$obj;  # 存在实例,直接返回实例
        }
        public function select(){
            echo "select *";
        }
}

$sobj1 = singleObj::getObj(); # 不存在实例 生成Obj #4
$sobj2 = singleObj::getObj(); # 存在实例 返回Obj #4
$sobj3 = singleObj::getObj(); # 存在实例 返回Obj #4
var_dump($sobj1);
var_dump($sobj2);
var_dump($sobj3);

为了防止对象从外部克隆时生成重复对象,还应当增加一个private function __clone(){}方法。
基本上,要实现单例模式,需要禁用构造方法和克隆方法,禁用的方法也很简单,只要加上private 修饰即可。

<?php

include '../config.php';

class getData{

    public $table;
    public $db;
    public  $link;

    public function __construct($table){
        
        $this->table = $table;
        $this->link = mysql_connect(DBHOST,DBUSER,DBPWD,DBNAME); 
        $this->db = mysql_select_db(DBNAME,$this->link);
       
    }

    private function query($query){  // 基础组件 执行SQL语句
        mysql_query("SET NAMES utf8");
        return mysql_query($query,$this->link);
    }

    public function get($limit){ // 功能: 获取条数为$limit条包含全字段数据的数据

        $query = "SELECT * FROM `".$this->table."`LIMIT 0 , $limit";
        $result = $this->query($query);
        return $this->toArray($result);
    }

    private function toArray($source){ // 基础组件 根据查询语句将数据打包成数组
       
        $arr = array();
        while($row = mysql_fetch_array($source)){
            $arr[] = $row;
        }
        return $arr;
    }
}


class read extends getData{
   
    function getDataArray($table,$limit){
        $data = new getData($table);
        return $data->get(10);
    }
}


$d =read::getDataArray('categories',10);
print_r($d);


# $d = getDataArray('categories',10); // 从表categories中获取包含10条全字段数据的数组
# print_r($d);

final 关键字

出于安全考虑,被final修饰的类无法继承,被final修饰的方法无法被重写,关键字final只能用来修饰类和方法。

class parentClass{

    final public function show(){
        echo "This is a class named parentClass";
    }

}

class childClass extends parentClass{

    public function show(){
        echo "This is a class named childClass";
    }

}

childClass::show();

/* 
#
# final 关键字只能用来修饰类和方法,final 修饰的类不能被继承,
# final 修饰的方法不能被重写
#
*/

以上代码输出:

Fatal error: Cannot override final method parentClass::show() in *_class.php on line 17

static 关键字

static 可以用来修饰成员属性和成员方法,以声明该属性和方法为静态,静态属性和静态方法不需要实例化即可访问,访问方法为类名::$静态属性|静态方法()

在类的内部引用静态属性和静态方法时,不可使用$this->$属性|方法(),而应该使用self::$属性|方法()。换句话说,如果类中的成员属性和成员方法使用了static修饰的话,如果需要在类的其他方法中引用它们,就必须使用self::$属性|方法()来调用。

const 关键字

如果需要在类的内部定义常量,则需要使用const关键字,其基本语法是 const CONSTANT = 'CONSTANT VALUE';。在类的内部访问常量则需要定义专有方法,在类的外部访问常量和访问及静态属性类似,只要使用类名::CONSTANT即可。

instanceof 关键字

这个关键字用来判断当前对象是否是某个类实例化而来,其基本语法是 $obj instanceof Class,会返回一个布尔结果。