zoukankan      html  css  js  c++  java
  • php核心技术与最佳实践知识点(上)

    一.基础

    1.serialize:序列化一个类,只是保存了类的属性,所以还需要反序列化unserialize的时候包含该类.

    2.对于将array转为object,这个转换因为没有具体的类,所以称为了一个孤类:

    <?php
    $arr = [1,2];
    var_dump((object) $arr);
    
    输出
    object(stdClass)#1 (2) {
      [0]=>
      int(1)
      [1]=>
      int(2)
    }
    

      

    3.其他语言的多态是向上转型,php的多态没有转型,只是调用了不同的派生类.

    4.接口是一种契约,但php的接口并不具备约束的能力.

    interface Engine
    {
        public function run();
    }
    
    class Car implements Engine
    {
        public function run()
        {
            echo 'run' . PHP_EOL;
        }
    
        public function fly()
        {
            echo 'fly' . PHP_EOL;
        }
    
    }
    
    function check(Engine $e) {
        $e->fly();
    }
    
    $car = new Car();
    check($car);
    

      

    我们在函数check中指明传入的参数应该是一个符合Engine的接口约束,但实际上并没有起到这个作用.php只关心传入的对象是否实现了接口中定义的方法,并不关心接口的语义是否正确.

    5.为了弥补php缺乏多重继承的缺陷,自php5.4.0起,php引入了Trait,实现代码复用.Trait可以被视为一种加强型的接口

    trait HelloWorld {
        public function sayHello() {
            echo 'Hello World!';
        }
    }
    
    class TheWorldIsNotEnough {
        use HelloWorld;
    }
    
    $o = new TheWorldIsNotEnough();
    $o->sayHello();
    

      

    6.反射API:ReflectionClass

    7.tokenizer
    tokenizer函数提供了一个内嵌在Zend引擎的"PHP tokenizer"的调用接口。使用这些函数,你可以写出你自己的PHP源码分析或者修改工具,而无需处理词法分析级别上的语言规范。

    示例代码:
    $tokens = token_get_all('<?php echo 1; ?>');
    print_r($tokens);
    

      

    8.php中的错误指脚本运行不正常,异常是业务流程不正常.php中的异常需要手动抛出,意义不是很大.

    9.set_error_handler():自定义错误,如果自定义错误,则错误抑制符失效.

    function handler($errorNo, $errorStr, $errorFile, $errorLine) {
        die($errorStr);
    }
    set_error_handler('handler', E_ALL);
    
    @$a[500];
    

      

    自定义错误和异常想结合的一个例子:

    function handler($errorNo, $errorStr, $errorFile, $errorLine) {
        throw new Exception($errorStr, $errorNo);
    }
    
    set_error_handler('handler', E_ALL);
    
    try {
        @$a[500];
    } catch (Exception $e) {
        echo $e->getMessage();
    }
    

      

    10.捕获致命错误fetal error:register_shutdown_function

    function shutdown()
    {
        //echo error_get_last();
        echo 'ok';
    }
    
    register_shutdown_function('shutdown');
    
    a;
    

      

    产生致命错误时,会回调shutdown,提供一些补救机会,但程序终止是必然的.

    11.语法错误(parse error)处理:计入日志,register_shutdown_function并不会对语法错误进行处理.

    php.ini
    log_error=on
    error_log=/usr/log/php-error.log
    

      

    12.触发错误:trigger_error

    <?php
    function test() {
        trigger_error('手动触发错误');
    }
    
    test();
    

      

    13.面向对象的一个基本例子:

    // domain
    class Message
    {
        public function setMsg()
        {
    
        }
    
        public function getMsg()
        {
    
        }
    }
    
    // model
    class MessageModel
    {
        // 从数据库读
        public function read()
        {
    
        }
    
        // 从数据库写
        public function write(Message $data)
        {
    
        }
    
        // 分页
        public function page()
        {
    
        }
    }
    
    // 逻辑层
    class LogicMessage
    {
        public function write(MessageModel $model, Message $data)
        {
            $model->write($data);
        }
    
        public function view(MessageModel $model)
        {
            return $model->read();
        }
    }
    
    // 控制器
    class ActionMessage
    {
        public function write(LogicMessage $logicMessage, MessageModel $model, Message $data)
        {
            $logicMessage->write($model, $data);
        }
    
        public function read(MessageModel $model)
        {
            return $model->read();
        }
    }
    
    // 调用
    $message = new Message();
    $logic = new LogicMessage();
    $model = new MessageModel();
    
    $action = new ActionMessage();
    $action->write($logic, $model, $message);
    $action->read($model);
    

      

    14.ignore_user_abort(true); //用户即便关闭网页,程序在后台执行不会中断.

    二.http协议

    1.cookie
    服务器发给客户端使用:Set-Cookie报头
    客户端发给服务器使用Cookie报头

    两者区别是Cookie报头的value可以有多个Cookie值,并且不需要指定domain;Set-Cookie只能有一个值,并且需要指明path和domain

    2.ip在tcp层传递,因此PHP中的SERVER或env变量中的HTTP_CLIENT_IP或REMOTE_ADDR,两者是难以伪造的.而HTTP_X_FORWARDED_FOR来自于与http请求中的X FORWARDED FOR报头,而这个报头是可以修改的.

    三.cUrl

    cUrl中的批处理,异步执行:
    
    $ch1 = curl_init();
    $ch2 = curl_init();
    
    curl_setopt($ch1, CURLOPT_URL, 'http://www.baidu.com');
    curl_setopt($ch1, CURLOPT_HEADER, 0);
    curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1);
    
    curl_setopt($ch2, CURLOPT_URL, 'http://news.baidu.com');
    curl_setopt($ch2, CURLOPT_HEADER, 0);
    curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1);
    
    $mh = curl_multi_init();
    
    curl_multi_add_handle($mh, $ch1);
    curl_multi_add_handle($mh, $ch2);
    
    // 执行批处理
    do {
        $mrc = curl_multi_exec($mh, $active);
    } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    
    
    while ($active and $mrc == CURLM_OK) {
    
        if(curl_multi_select($mh) === -1){
            usleep(100);
        }
        do {
            $mrc = curl_multi_exec($mh, $active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    
    }
    
    // 获取内容
    $content1 = curl_multi_getcontent($ch1);
    $content2 = curl_multi_getcontent($ch2);
    
    // 移除句柄,否则造成死循环
    curl_multi_remove_handle($mh, $ch1);
    curl_multi_remove_handle($mh, $ch2);
    
    curl_multi_close($mh);
    
    
    echo $content1;
    echo $content2;
    

      

    四.cookie

    1.setrawcookie和setcookie的区别是,前者不对值进行urlencode

    2.php并没有设置cookie,只是通知浏览器来设置cookie.cookie设置在当前页不会生效,在下一个页面才会生效.

    3.cookie是http头的一部分,因此在设置cookie前,不能有输出.

    4.每个域名下允许的cookie是有限制的,ie8是50个,firefox是150个

    5.一个域名的每个cookie限制大小为4kb

    五.session

    1.php.ini中的Session设置中的session.save_path="N;MODE;/path"
    N:表示目录级数;如为2表示2级目录存放,每一级有0-9和a-z共36个字符作为目录名,2级则可以有36*36个目录
    MODE:表示目录权限,默认为600
    path:表示存放路径

    2.对于设置分级目录存储的session,php不会自动回收,需要自己实现回收机制

    3.访问量大的站点,默认的文件session并不适合,可以用数据库或内存缓存

    六.基本SQL优化的十个原则

    1.避免在列上进行运算,这将使索引失效.
    SELECT * FROM table WHERE YEAR(d) > 2017;

    优化为
    SELECT * FROM table WHERE d > '2017-01-01;

    2.使用join时,小结果集驱动大结果集,同时把复杂的join查询拆分为多个query.因为join多个表时,导致更多的锁定和阻塞.

    内联结时MySQL自动用小结果集驱动大结果集.
    左联结和右联结,则需要作出优化

    3.避免like的模糊查询
    select * from user where username like '%u%';

    优化为:
    select * from user where username >= 'u' AND username < 'v';

    select * from user where username like 'u%';

    4.列出仅需要的字段,这对速度不会有影响,主要考虑节省内存.
    select * from user where username >= 'u' AND username < 'v';

    优化为
    select id from user where username >= 'u' AND username < 'v';

    5.使用批量插入,节省交互
    insert into table values('a', 'b', 'c');
    insert into table values('a', 'b', 'c');
    insert into table values('a', 'b', 'c');

    优化为:
    insert into table values('a', 'b', 'c'),('a', 'b', 'c'),('a', 'b', 'c');

    6.limit基数比较大时使用between
    select * from user order by id asc limit 1000000,10

    优化为:
    select * from user where id between 1000000 and 1000010 order by id asc

    但是如果有断行,该项将不适用 .

    7.不用使用rand返回随机数据.

    8.避免使用NULL,MYSQL难以优化引用了可空列的查询

    9.不用使用count(id),而应使用count(*)

    10.不要做无谓的排序操作,应尽可能在索引中完成排序.

    七.MySQL

    1.explain:保证type达到range级别,最好是ref级别,All为全表扫描,这是最坏的情况
    2.简单的确定读写比例(R/W):
    show global status;

    com_select为读,com_update+com_insert为写
    如果R/W小于10:1,则认为是以写为主的数据库.


    3.MyISAM:适当增加key_buffer_size;可以根据key_cache的命中率进行计算
    show global status like 'key_read%';

    缓存未命中率:key_cache_miss_rate=Key_reads/Key_read_requests * 100%,如果大于1%就要适当增加key_buffer_size

    还要注意table_cache的设置.如果该值过小,mysql就会反复打开,关闭frm文件.如果过大,又会造成cpu的浪费.一个合理的办法是观察opened_tables的值,如果持续增长,就要增加table_cache的值.


    4.InnoDB:重点注意innodb_buffer_pool_size;

    5.从表中删除大量行时,可运行 optimize table tableName;

    八.MySQL模拟消息队列


    0:流程:
    用户发布一篇文章(insert into article),触发tigger_insert_feed,向feed表插入一条动态,触发tigger_insert_queue,定时器event_push_broadcast每1分钟从queue中提取数据到feed_broadcast.

    1.新建user表
    CREATE TABLE `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` char(255) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=gbk;

    2.新建friend表
    CREATE TABLE `friend` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `uid` int(11) DEFAULT NULL,
    `fuid` int(11) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=gbk;

    3.新建feed_broadcast
    CREATE TABLE `feed_broadcast` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `uid` int(11) DEFAULT NULL,
    `title` char(255) DEFAULT NULL,
    `is_read` tinyint(4) DEFAULT '0' COMMENT '是否已读',
    `time` int(11) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=gbk;

    4.新建article表
    CREATE TABLE `article` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `uid` int(11) DEFAULT NULL,
    `title` char(255) DEFAULT NULL,
    `time` int(11) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=gbk;

    建立触发器trigger_insert_feed
    create trigger trigger_insert_feed after insert on article for each row
    begin
    insert into feed(uid,article_id,content,time) values(New.uid, New.id,'发布了文章',New.time);
    end

    5.新建feed表
    CREATE TABLE `feed` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `uid` int(11) NOT NULL,
    `article_id` int(11) NOT NULL,
    `content` varchar(500) NOT NULL,
    `time` int(11) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=gbk;

    建立触发器trigger_insert_queue
    create trigger trigger_insert_queue after insert on feed for each row
    begin
    insert into queue(uid,feed_id,content,status,time) values(New.uid,New.id,'发布了文章',0,New.time)
    end

    6.建立queue表:
    CREATE TABLE `queue` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `uid` int(11) NOT NULL,
    `feed_id` int(11) NOT NULL,
    `content` varchar(500) NOT NULL,
    `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0未未处理,1为处理',
    `time` int(11) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=gbk


    7.创建存储过程push_broadcast:
    CREATE DEFINER=`root`@`localhost` PROCEDURE `push_broadcast`()
    BEGIN
    insert into feed_broadcast(uid,title,time) select ef.fuid,tmp.content,tmp.time from (select * from queue where status=0 order by id desc limit 10) tmp,friend ef where tmp.uid=ef.uid;
    update queue set status=1 where status=0 order by id desc limit 10;
    END

    8.创建一个定时事件event_push_broadcast:
    CREATE DEFINER=`root`@`localhost` EVENT `event_push_broadcast` ON SCHEDULE EVERY 1 MINUTE STARTS '2017-11-12 17:53:58' ON COMPLETION NOT PRESERVE ENABLE DO call push_broadcast()


    查看event_scheduler是否是开启状态
    show global variables like '%sche%';

    如果event_scheduler为off;
    开启:
    set global event_scheduler=on;

    9.至此可以插入数据做测试了

  • 相关阅读:
    Java中的数据类型
    java中变量的分类
    软考视频总结(二)——细化学习A
    软考视频总结(一)——蜕变
    Eclipse汉化
    IIS 服务或万维网发布服务,或者依赖这两种服务的某个服务未能启动。
    jQuery--编辑表格
    MVC之查询demo
    初识MVC之建项
    附加数据库 对于服务器 XXX失败
  • 原文地址:https://www.cnblogs.com/itfenqing/p/7822407.html
Copyright © 2011-2022 走看看