MySQL数据表生成Wiki格式数据字典

<?php
$dbms='mysql';     //数据库类型
$host='localhost'; //数据库主机名
$dbName='joyous';    //使用的数据库
$user='test';      //数据库连接用户名
$pass='123456';          //对应的密码
$dsn="$dbms:host=$host;dbname=$dbName";

$table = array(
    't_user' => '用户表',
    't_user_info' => '用户扩展信息表',
 
);
try {
    $dbh = new PDO($dsn, $user, $pass); //初始化一个PDO对象
    $dbh->query('set names utf8');
    foreach ($table as $k => $v) {
        echo "### {$k}({$v})\n\n";
        $res = $dbh->query("SHOW FULL FIELDS FROM {$k}");
        $res->execute();
        $result = $res->fetchAll();
        echo "| 参数名称 | 类型 | 非空约束 | 备注说明|\n| ------ | ------ | ------ | ------ |\n";
        foreach ($result as $row)
        {
            echo "|{$row[0]}|{$row[1]}|{$row[3]}|{$row[8]}|\n";
        }
        echo "\n\n";
    }
} catch (PDOException $e) {
    echo $e->getMessage();
}

坑爹的BOM

场景:开发小程序使用wx.request请求数据时提示Cannot read property of ‘xxxx’ undefined……..

原因:request返回的数据会默认会经过JSON.parse函数转换为Object,如果返回内容带有BOM就会影响转换

解决办法:

1.服务器端返回数据去除BOM(一般的IDE都有这样的功能)

2.编写兼容代码(在小程序内wx.request设置dateType:’text’,然后将返回的res.data进行去除字符res.data.trim()处理之后调用JSON.parse转换)

小程序wx.uploadFile失败的问题排查记录

现象:部分安卓(华为meta9)下用canvas画图之后使用wx.canvasToTempFilePath保存文件,然后再使用wx.uploadFile上传到服务器,上传图片失败

尝试方案:

1、canvasToTempFilePath延迟执行(怀疑是不是生成图需要时间,就加了延迟执行) ,结果:还是不能上传

2、设定header(网上有说编码的问题,我设置了header)
 header: {
      ‘content-type’: ‘multipart/form-data’
    },
结果:还不能上传

3、服务器记录的日志当中看到华为上传的FILE是这样的

最终解决方案:

服务器端判断上传文件类型,通过file_put_contents写入到文件

结果:成功

备注:

这个图片导出同样是安卓机器,在小米5导出是这样的

而且华met9上是这样的

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;

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层的设计,着重于业务的实现,因此不可避免的以贫血模式为基础而存在。