PHP取余的那些事

1、百分号取余

$val=9.45; 
$result=$val*100;
echo intval($result);   //这里输出944
echo $result%100;    //这里输出44
echo fmod(floatval($result),100);  //这里输出45

解释:因为php默认对变量进行取整进行取余运算的

2、取余溢出

<?php
$num1 = 1494313163777;
$num2 = 9999;
//直接计算取余会出错,出现负数 -8779
echo $num1 % $num2;

//解决方案:
$num1 = floatval($num1);
$luck_num = fmod($num1, $num2);
//显示38正确
echo $luck_num;

SSI说明

一、SSI
Server Side Include,是一种基于服务端的网页制作技术,大多数(尤其是基于Unix平台)的web服务器如Netscape Enterprise Server等均支持SSI命令。
它的工作原因是:在页面内容发送到客户端之前,使用SSI指令将文本、图片或代码信息包含到网页中。对于在多个文件中重复出现内容,使用SSI是一种简便的方法,将内容存入一个包含文件中即可,不必将其输入所有文件。通过一个非常简单的语句即可调用包含文件,此语句指示Web服务器将内容插入适当网页。而且,使用包含文件时,对内容的所有更改只需在一个地方就能完成。

二、Nginx配置
ssi: 默认值off,启用ssi时将其设为on
ssi_silent_errors: 默认值off,开启后在处理SSI文件出错时不输出错误提示”[an error occurred while processing the directive]”。
ssi_types: 默认是text/html,所以如果需支持html,则不需要设置这句,如果需要支持shtml则需要设置:ssi_types text/shtml
三个参数可以放在http, server或location作用域下

三、Apache配置
AddType text/html .shtml .html
AddOutputFilter INCLUDES .shtml .html
Options Indexes FollowSymLinks INCLUDES IncludesNOEXEC

四、file和virtual
file可以包含一些指令,virtual不可以

五、语法
<!–#include virtual=”test.html” –>

&lt;!--#include file="test.html"--&gt;

参考:http://man.chinaunix.net/newsoft/ApacheManual/howto/ssi.html

http://nginx.org/en/docs/http/ngx_http_ssi_module.html

Composer

Composer是PHP中用来管理依赖(dependency)关系的工具。你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer会帮你安装这些依赖的库文件。

如果A依赖B的版本是1.0.0,如果C依赖B的版本是2.0.0,项目当中是否没导入同一包用不同版本的。

PHP的自动加载可以使用__autoload()和spl_autoload_register()两种机制,但官方推荐使用和spl_autoload_register
更多参考:http://php.net/manual/zh/language.oop5.autoload.php

Composer提供了四种自动加载的方式,分别是PSR-0、PSR-4、生成classmap以及直接包含files。
PSR-0要求目录名称和命名空间层层对应,会导致目录结构容易变得比较深。虽然已被官方废弃,但因为主流框架都已实现psr-0,因此composer仍然使用psr-0来向下兼容。按照PSR-0的规则,当试图自动加载 “Foo\Bar\Baz” 这个class时,那么会去寻找”src/Foo/Bar/Baz.php”。

psr-4方式,是composer推荐使用的一种方式,也是psr-0的替代方案,因为在PSR-0中目录结构要与命名空间层层对应,无法插入一个单独的目录。

classmap方式,则是通过配置指定的目录或文件,然后在Composer安装或更新时,它会扫描指定目录下以.php或.inc结尾的文件中的class,生成class到指定file path的映射,并加入新生成的 vendor/composer/autoload_classmap.php 文件中

files方式,就是手动指定供直接加载的文件

PHP反射机制

PHP反射机制它是用来导出或提取出关于类、方法、属性(私有保护等属性也能获取)、参数等的详细信息,包括注释。

<?php

class Test{
    public $var1 = 'var1';
    public $var2 = 'var2';
    private $var3 = 'var3';
    public function method1() {
        echo '1';
    }
    public function method2(){
        echo '2';
    }
    private function method3($v1, $v2, $v3) {
        echo '3' . $v1;
    }
}
print_r(get_class_methods('Test'));
print_r(get_class_vars('Test'));
//用反射类可以获得私有属性和私有方法
$ref = new ReflectionClass(new Test());
print_r($ref->getMethods());
print_r($ref->getProperties());

//执行私有方法
$ref = new ReflectionMethod('Test', 'method3');
$params  = $ref->getParameters();
$arg = [];
foreach ($params as $param) {
    if($param->getName()) {
        $arg[] = '参数1';
    }
}
//设置可见
$ref->setAccessible(true);
$ref->invokeArgs(new Test(), $arg);

更多内容参考:http://php.net/manual/zh/book.reflection.php

php使用elasticsearch

1.引入包
composer require elasticsearch/elasticsearch

2.DEMO参考

<?php
require_once './vendor/autoload.php';

use Elasticsearch\ClientBuilder;

$hosts = [
    [
        'host' => '192.168.56.201',
        'port' => '9200',
        'scheme' => 'http',
        //'user' => 'username',
        //'password' => 'password'
    ],
];
try {
    $client = ClientBuilder::create()->setHosts($hosts)->build();
    //创建index并设置mapping
    /*$params = [
        'index' => 'demo',  //索引名(相当于关系型mysql的数据库)
        'body' => [
            'settings' => [
                'number_of_shards' => 1,  //分片数
                'number_of_replicas' => 1, //副本分骗术
            ],
            'mappings' => [
                'm_type' => [
                    '_all' => [
                         'enabled' => 'false'
                    ],
                    '_routing' => [
                        'required' => 'true'
                    ],
                    'properties' => [ //文档类型设置(相当于mysql的数据类型)
                        'name' => [
                            'type' => 'string',
                            'store' => 'true'
                        ],
                        'age' => [
                            'type' => 'integer'
                        ]
                    ]
                ]
            ]
        ]
    ];
    $response = $client->indices()->create($params);
    print_r($response);//Array ( [acknowledged] => 1 [shards_acknowledged] => 1 )
    */
//    索引操作
//    $params = [
//        'index' => 'demo',
//    ];
//    $response = $client->indices()->delete($params);    //删除索引
//    print_r($response);//Array ( [acknowledged] => 1 )
    //$response = $client->indices()->getSettings($params);//获取索引设置信息
    //print_r($response);//Array ( [demo] => Array ( [settings] => Array ( [index] => Array ( [creation_date] => 1502246895144 [number_of_shards] => 5 [number_of_replicas] => 5 [uuid] => tW3DB-9FRQC2W-bwXl0fbg [version] => Array ( [created] => 5040199 ) [provided_name] => demo ) ) ) )
    //$response = $client->indices()->exists($params);   //检测索引是否存在
    //print_r($response);//1
    //$response = $client->indices()->getMapping($params);   //获取索引的mapping信息
    //print_r($response);//Array ( [demo] => Array ( [mappings] => Array ( [m_type] => Array ( [_all] => Array ( [enabled] => ) [_routing] => Array ( [required] => 1 ) [properties] => Array ( [age] => Array ( [type] => integer ) [name] => Array ( [type] => text [store] => 1 ) ) ) ) ) )
    
    //添加文档
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        'body' => [
//            'name' => 'demo',
//            'age' => 150
//        ],
//        'routing' => '/demo/m_type'
//    ];
//    $response = $client->index($params);
//    print_r($response);
  
    //删除文档
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        'routing' =>   '/demo/m_type'
//    ];
//    $response = $client->delete($params);
//    print_r($response);//Array ( [found] => 1 [_index] => demo [_type] => m_type [_id] => 1 [_version] => 2 [result] => deleted [_shards] => Array ( [total] => 2 [successful] => 2 [failed] => 0 ) )
    
    //修改文档
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        'body' => [
//            'doc' => [
//                'name' => 'demo22',
//                'age' => 130
//            ]
//        ],
//        'routing' =>   '/demo/m_type'
//    ];
//    $response = $client->update($params);
//    print_r($response);
    //获取文档并指定字段
//    $params = [
//        'index' => 'demo',
//        'type' => 'm_type',
//        'id' => '2',
//        '_source' => [
//            'age'
//        ],
//        'routing' =>   '/demo/m_type'
//    ];
//    $response = $client->get($params);
//    print_r($response);
//    $response = $client->getSource($params);
//    print_r($response);
    
    //高级搜索
//    $params = [
//        'index' => 'demo',
//        'type'  => 'm_type',
//        'routing' => '/demo/m_type',
//        'body' => [
//            'query' => [
//                'match' => [
//                    'age' => 130,
//                ]
//            ]
//        ]
//    ];
//    $response = $client->search($params);
//    print_r($response);
    
} catch (Exception $e) {
    echo $e->getMessage();
}

备注:如果提示routing_missing_exception则参数当中需要传递routing

参考:https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html

PHPUnit使用笔记

1.引入composer
composer require  phpunit/phpunit

2.编写测试代码

<?php
require_once './vendor/autoload.php';
require_once './Demo.php';

use PHPUnit\Framework\TestCase;
use Mydemo\Demo;
class DemoTest extends TestCase
{
    public function testone()
    {
        //判断真假
        $this->assertTrue(Demo::add(1,2) == 3);
        //判断总数是否正确
        $this->assertEquals(5, count(Demo::fetchAll()));
        //判断结果是否包含
        $this->assertContains(1, Demo::fetchAll());
    }
}
更多内容参考:https://phpunit.de/manual/current/zh_cn/appendixes.assertions.html

3.编写类

<?php

namespace Mydemo;

class Demo
{
    public static function add($a, $b)
    {
        return $a + $b;
    }
    
    public static function fetchAll()
    {
        return [1,2,3,4,5];
    }
}

TDD、BDD和DDD

1.TDD,测试驱动开发
TDD指的是Test Drive Development,简单地说,TDD 就是在写代码前先写测试,并严格遵守(错误》正确》重构)的流程

2.BDD,行为驱动开发
BDD指的是Behavior Drive Development,实际上BDD可以看作是对TDD的一种补充,当然你也可以把它看作TDD的一个分支

3.DDD,领域驱动开发
DDD是指Domain Drive Design,也就是领域驱动开发,这是一种非常好的思想。在我们刚开始学习程序,甚至刚开始学习三层架构的时候,我们曾经面临过很多疑惑,比如如何来实现我们的数据层?后来我们开始学习MVC,MVP等架构,如何设计Model层又成了我们的新问题。我们见过太多这种情况,Model变成了单纯的数据容器,也就是我们经常说的贫血模式。DDD实际上也是建立在这个基础之上,因为它关注的是Service层的设计,着重于业务的实现,因此不可避免的以贫血模式为基础而存在。

monolog使用案例

1.首先要执行
composer require monolog/monolog
2.案例
<?php
require_once './vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\RedisHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\BrowserConsoleHandler;
use Monolog\Processor\WebProcessor;
use Monolog\Processor\IntrospectionProcessor;

use Monolog\Formatter\JsonFormatter;

$logfilename = "/data/logs/default/" .date('YmdH').".log";
$redis = new Redis();
$redis->connect('192.168.56.101',6379);
$key  = 'monolog';

$stream = new StreamHandler($logfilename,Logger::ERROR);
$stream->setFormatter(new JsonFormatter());

$redishandle = new RedisHandler($redis,$key,Logger::INFO);

$browserhandle = new BrowserConsoleHandler(Logger::INFO);

$channel1 = 'test';

$log = new Logger($channel1);
$log->pushHandler($stream);
$log->pushHandler($redishandle);
$log->pushHandler($browserhandle);

$log->pushProcessor(new WebProcessor());
$log->pushProcessor(new IntrospectionProcessor());


$log->info('info', ['a' => 'test']);
$log->error('error');

monolog使用解析

1.channel渠道、通道
可以区分同项目不同模块日志

2.handler处理器
一个channel设置多个handler,是按照堆栈的方式依次调用(后进先出,最后调用的先执行),方便将日志发送多个接收器(redis、elasticsearch、syslog等)
备注:可以自己根据自己需求实现handler

3.processor扩展信息
一个channel可以附带一些扩展信息,可以用来补充一些额外信息(内存、进程、服务器IP等信息)也可以用来记录上下文信息
备注:可以自己根据自己需求实现processor,上下文信息也可以使用扩展的数组传递

4.formatter格式化信息
每个handler可以设定特定的格式化信息(默认是LineFormatter)
备注:可以自己根据自己需求实现formatter

5.level日志等级
每个handler设定处理特定级别的日志

DEBUG(100)详细的DBUG信息
INFO(200) 提示信息,感兴趣的信息
NOTICE(250)通知信息,重大意义的信息
WARNING(300)警告信息,异常信息
ERROR(400)错误信息
CRITICAL(500)关键错误信息,内部组件错误
ALERT(550)依赖服务不可以用,例如数据库故障灯
EMERGENCY(600)系统不可用
备注:错误日志数字越大,表示错误越严重,如果一个handler设置的日志级别较低则可以处理较高级别的日志信息

MySQL最大连接数和当前并发数

1.查看当前连接数和并发
执行:show status like ‘Threads%’;
+——————-+——-+
| Variable_name     | Value |
+——————-+——-+
| Threads_cached    | 220   |
| Threads_connected | 16    |
| Threads_created   | 236   |
| Threads_running   | 3     |
+——————-+——-+

Threads_connected 跟show processlist结果相同,表示当前连接数,Threads_running是代表当前并发

2.查看最大连接数
执行:show variables like ‘%max_connections%’;
+—————–+——-+
| Variable_name   | Value |
+—————–+——-+
| max_connections | 1200  |
+—————–+——-+