PHP 从菜鸟到大咖的踩坑之路

https://cloud.tencent.com/developer/article/1464655 电商Sku设计思维

https://xlswriter-docs.viest.me/zh-cn/an-zhuang/mac 借助C扩展来 处理百万 excel文件的导入导出

https://juejin.im/post/6867433557313863688 数组巧用

https://juejin.im/post/6844904093735976974 来源不一样的数据分页

https://juejin.im/post/6844904180834893832 curl_multi并发请求

https://juejin.im/post/6844903849132556296 排查系统为啥会运行缓慢

https://juejin.im/post/6844904194734817287 本地环境搭建 docker

个人微信消息推送 http://sc.ftqq.com/?c=code

#php调用代码
file_get_contents('https://sc.ftqq.com/SCU144549Te2356489fe44a621fd109f8f7484e9dd5ff2878ccf662.send?text=not_complete_sync_order订单同步失败');

function sc_send(  $text , $desp = '' , $key = 'SCU144549Te2356489fe44a621fd109f8f7484e9dd5ff2878ccf662'  )
{
    $postdata = http_build_query(
    array(
        'text' => $text,
        'desp' => $desp
    )
);

$opts = array('http' =>
    array(
        'method'  => 'POST',
        'header'  => 'Content-type: application/x-www-form-urlencoded',
        'content' => $postdata
    )
);
$context  = stream_context_create($opts);
return $result = file_get_contents('https://sc.ftqq.com/'.$key.'.send', false, $context);

}

时间范围

//获取今日开始时间戳和结束时间戳
 $start = mktime(0,0,0,date('m'),date('d'),date('Y'));
 $end = mktime(0,0,0,date('m'),date('d')+1,date('Y'))-1;
 //获取昨日起始时间戳和结束时间戳
 $beginYesterday = mktime(0,0,0,date('m'),date('d')-1,date('Y'));
 $endYesterday = mktime(0,0,0,date('m'),date('d'),date('Y'))-1;
 //获取上周起始时间戳和结束时间戳
 $beginLastweek = mktime(0,0,0,date('m'),date('d')-date('w')+1-7,date('Y'));
 $endLastweek = mktime(23,59,59,date('m'),date('d')-date('w')+7-7,date('Y'));
 //获取本月起始时间戳和结束时间戳
 $beginThismonth=mktime(0,0,0,date('m'),1,date('Y'));
 $endThismonth=mktime(23,59,59,date('m'),date('t'),date('Y'));
strtotime(date('Y-m-d 9:30:00',time()));  

laravel whereor 查询

$extra = $params['extra'];
        $handle->where(function ($query) use ($extra) {
            $query->where('admin_name', 'like', "%$extra%")->orWhere('title', 'like', "%$extra%");
        });

array_walk 和 array_map && array_reduce && array_filter && array_flip 使用

#array walk以引用传递的形式遍历你的数组,没有返回值,而且只能处理一个数组
$arr = ['a', 'b', 'c'];

array_walk($arr, function (&$item) {
    $item = $item . '_i';
});
print_r($arr); // ['a_i', 'b_i', 'c_i'];

#array_map 使用匿名函数的方式,处理数组里的每个元素。遍历完成后返回一个新的数组,并且可以同时处理多个数组
$arr_1 = ['a', 'b', 'c'];
$arr_2 = ['你', '好', '吗', '原', '罪'];

$arr = array_map(function ($item_1, $item_2) {
    return $item_1 . '_' . $item_2 . '_i';
}, $arr_1, $arr_2);  如果需要获取下标的可以使用 array_keys($arr_1)代替$arr_2

print_r($arr); // ['a_你_i', 'b_好_i', 'c_吗_i', '_原_i', '_罪_i']

#array_reduce() 函数向用户自定义函数发送数组中的值,并返回一个字符串。
  $arr = [
     0 => '全部',
     1 => 'a',
     2 => 'b',
     3 => 'c',
    ];
$index   = 0;
$options = array_reduce($arr, function($carry, $item) use (&$index){
    ## $index则为当前两个元素 $item 的索引
    return $carry . '<option value="' . $index++ . '">' . $item . '</option>';
}, '');

var_dump($options);return;
#过滤数组中的内容
   $data = [
    [ 'id' => 1, 'name' => '你好,234', 'cate' => '生活日记'],
    [ 'id' => 2, 'name' => '79798', 'cate' => '摄影美图'],
    [ 'id' => 3, 'name' => '567567', 'cate' => '生活日记'],
   ];

$filtered = array_filter($data, function($item){
    return $item['cate'] !== '摄影美图';
});
print_r($filtered);return;

#翻转数组去重
array_flip (array_flip($trans)); 
#移除数组中重复的值:
array_unique($arr);   
#array_flip  和 array_unique区别 array_flip 会保留重复值最后一个,array_unique 只保留重复值的第一个

数组遍历思想

==数组嵌套循环的时候最内层的遍历完之后指针为空才开始向外层一层一层遍历直到指针遍历完改层数组==

==foreach()嵌套foreach都会先把本身{}内的循环完,再进行下一次循环,从里往外开始==

==数组元素多的嵌套数组元素少的。小建议==

==循环从上往下 从左往右。循环套循环的,程序执行到里面一次要循环完了,外面的才会进行第二次循环==

php处理大数文件问题

尽可能使用文件操作,不要直接导入到数组库,过程很慢

php操作大数组减少内存方法

<?php
$start_mem = memory_get_usage();
function yield_range( $start, $end ){
  while( $start <= $end ){
    $start++;
    yield $start;
  }
}
foreach( yield_range( 0, 9999 ) as $item ){
  echo $item.',';
}
$end_mem = memory_get_usage();
echo " use mem : ". ( $end_mem - $start_mem ) .'bytes'.PHP_EOL;

# 操作大文件 
<?php
header("content-type:text/html;charset=utf-8");
function readTxt()
{
    # code...
    $handle = fopen("./test.txt", 'rb');

    while (feof($handle)===false) {
        # code...
        yield fgets($handle);
    }

    fclose($handle);
}

foreach (readTxt() as $key => $value) {
    # code...
    echo $value.'<br />';
}


mysql 常用查询

导出数据表结构说明

//首先选择mysql里面的information_schema库
SELECT 
    COLUMN_NAME 字段名称,
    COLUMN_TYPE 数据类型,
    IS_NULLABLE 是否为空,
    COLUMN_COMMENT 字段描述 
FROM
COLUMNS 
WHERE
    TABLE_NAME = 'fr_activity_component' group by COLUMN_NAME ORDER BY ORDINAL_POSITION
//执行后导出excel

修改一个字段为随机数

update fr_topic set post_num = ceiling(rand()*3000+9000) WHERE  1=1 

时间戳转换

FROM_UNIXTIME(a.end_time) 格式化时间

UNIX_TIMESTAMP('2006-11-04 12:23:00'); 格式化成时间戳

把查询出来的一个结果集的sql 某个字段用标识符分割

SELECT  GROUP_CONCAT(a.`sku_id` separator ',;cc') 账号 from fr_goods_sku a LEFT JOIN fr_goods b  on a.goods_id =b.goods_id where b.type = 1 AND sku_image_url !='' limit 20;

子查询操作

DELETE from fr_users_bargain where user_id  IN (SELECT user_id from (SELECT user_id,count(slash_id) as ids FROM fr_users_bargain  where cate = 2 GROUP BY user_id HAVING ids > 1) ee)

json 问题 中文和反斜杠被转义

json_encode($post_data,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)

curl请求问题排查

  $response = curl_exec($ch);
  $errorno = curl_errno($ch);
  $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

先根据 curl_errno 查看状态码 然后去
https://www.php.net/manual/zh/function.curl-errno.php 查看状态码的对应报错

读取大文件

读取大文件方法
<?php
 function yieldCommand($fileName) {
 $line = [];
 $handle = fopen($fileName, "r"); 
     while (!feof($handle)) {
        yield ltrim(fgets($handle));
     } 
     fclose($handle); 
 } 
 foreach (yieldCommand("name.txt") as $key => $value) {
     echo $value; 
 } 
 require "memory.php"; ?>

安装pcntl

https://icharle.com/macpcntl.html

sudo wget https://www.php.net/distributions/php-7.1.26.tar.gz

tar -zxvf php-7.1.26.tar.gz

cd php-7.1.26 && cd ext && cd pcntl

/Applications/MAMP/bin/php/php7.1.26/bin/phpize php --ini 找到安装的php路径 使用里面的 phpize 在pcntl目录下执行

/configure --with-php-config=/Applications/MAMP/bin/php/php7.1.2/bin/php-config

make && make install

php --ri swoole

php -i | grep php.ini

sudo wget https://www.php.net/distributions/php-7.3.7.tar.gz

数组操作

if (!function_exists('hideStr')) {

    /**
     * [hideStar 用户名、邮箱、手机账号中间字符串以*隐藏]
     * @param  [string] $str [传过来字符串]
     * @return [string]      [返回带*字符串]
     */
    function hideStr($str)
    {
        if (strpos($str, '@')) {
            $email_array = explode("@", $str);
            $prevfix = (strlen($email_array[0]) < 4) ? "" : substr($str, 0, 3);
            $count = 0;
            $str = preg_replace('/([\d\w+_-]{0,100})@/', '***@', $str, -1, $count);
            $rs = $prevfix . $str;
        } else {
            $pattern = '/(1[3458]{1}[0-9])[0-9]{4}([0-9]{4})/i';
            if (preg_match($pattern, $str)) {
                $rs = preg_replace($pattern, '$1****$2', $str);
            } else {
                $rs = substr($str, 0, 3) . "***" . substr($str, -1);
            }
        }
        return $rs;
    }
}

if (!function_exists('format_timestamp')) {
    function format_timestamp($timestamp, $format = "Y.m.d H:i:s")
    {
        return $timestamp <= 0 ? '-' : date($format, (int)$timestamp);
    }
}

if (!function_exists('get_countdown_second')) {
    function get_countdown_second($time)
    {
        return $time - time() < 0 ? 0 : $time - time();
    }
}


if (!function_exists('get_countdown_second')) {
    function number_format($number, $flag = 2)
    {
        return sprintf("%" . $flag . "f", $number);
    }
}


/**
 * 保留几位小数,向下取整
 *$num 要处理的浮点数
 *$digits 要保留的小数位数
 * 实现思路:先乘以10的小数位数次方,用floor向下取整,再除以除数得到舍去后面位数的结果
 * 最后再用sprintf配合位数再取一次值(此处是为了解决有些数字属,最后一位为零时不显示问题)
 */
if (!function_exists('floorFloat')) {
    function floorFloat($num, $digits)
    {
        $num = floatval($num);
        $multiple = pow(10, $digits);
        $tempNum = floor($num * $multiple);
        return sprintf('%.' . $digits . 'f', $tempNum / $multiple);
    }
}

二维数据进行排序
if(!function_exists('arraySequence')){
    /**
     * 二维数组根据字段进行排序
     * @params array $array 需要排序的数组
     * @params string $field 排序的字段
     * @params string $sort 排序顺序标志 SORT_DESC 降序;SORT_ASC 升序
     */
    function arraySequence($array, $field, $sort = 'SORT_ASC')
    {
        $arrSort = array();
        foreach ($array as $uniqid => $row) {
            foreach ($row as $key => $value) {
                $arrSort[$key][$uniqid] = $value;
            }
        }
        array_multisort($arrSort[$field], constant($sort), $array);
        return $array;
    }
}




二维数组转一维数组   array_column();

二维数组去重

function remove_duplicate($array){
  $result=array();
  foreach ($array as $key => $value) {
    $has = false;
    foreach($result as $val){
      if($val['id']==$value['id']){
      $has = true;
      break;
    }
  }
if(!$has)
  $result[]=$value;
}
return $result;
}

过滤一个数组在另一个数组中出现的 。
var arr1 = ["i", "b", "c", "d", "e", "f","x"]; //数组A  
var arr2 = ["a", "b", "c", "d", "e", "f", "g"];//数组B  

var temp = []; //临时数组1  
var temparray = [];//临时数组2  
for (var i = 0; i < arr2.length; i++) {  
    temp[arr2[i]] = true;//巧妙地方:把数组B的值当成临时数组1的键并赋值为真  
}
for (var i = 0; i < arr1.length; i++) {  
    if (!temp[arr1[i]]) {  
        temparray.push(arr1[i]);//巧妙地方:同时把数组A的值当成临时数组1的键并判断是否为真,如果不为真说明没重复,就合并到一个新数组里,这样就可以得到一个全新并无重复的数组  
    } 
}
document.write(temparray.join(",") + ""); 



/*
 * 计算倒计时
 * @param unix时间格式
 * @return string
 */
function dealTime($endTime) {

    $t = $endTime - time();


    if ($t <= 0) return '';

    $str = '';

    if ($t > 86400) {
        $days = floor($t / 86400);
        
        $t = $t - (86400 * $days);
        $str .= $days . '天';
    } 
 

    if ($t > 3600) {
        $hours = floor($t / 3600);
        $t = $t - (3600 * $hours);
        $str .= $hours . '时';
    }

    if ($t > 60) {
        $minu = floor($t / 60);
        $t = $t - (60 * $minu);  
        $str .= $minu  . '分';
    }

    $str .= $t . '秒';

    return $str;
}

/**
 * 隐藏部分电话号码,手机号隐藏中间四位
 * @param strint $phone
 * @return string
 */
function hidetel($phone){
    $IsWhat = preg_match('/(0[0-9]{2,3}[-]?[2-9][0-9]{6,7}[-]?[0-9]?)/i', $phone); //固定电话
    if ($IsWhat == 1) {
        return preg_replace('/(0[0-9]{2,3}[-]?[2-9])[0-9]{3,4}([0-9]{3}[-]?[0-9]?)/i','$1****$2', $phone);
    } else {
        return  preg_replace('/(1[35678]{1}[0-9])[0-9]{4}([0-9]{4})/i','$1****$2', $phone);
    }
}

/**
 * 随机生成颜色值
 * 
 * 
 */
function randcol() 
{ 
  $str='0123456789ABCDEF'; 
    $estr='#'; 
    $len=strlen($str); 
    for($i=1;$i<=6;$i++) 
    { 
        $num=rand(0,$len-1);   
        $estr=$estr.$str[$num];  
    } 
    return $estr; 
}

/**
 * 将xml转为array
 * @param  string   $xml xml字符串或者xml文件名
 * @param  bool     $isfile 传入的是否是xml文件名
 * @return array    转换得到的数组
 */  
function xmlToArray($xml,$isfile=false){
    //禁止引用外部xml实体  
    libxml_disable_entity_loader(true);
    if($isfile){
        if(!file_exists($xml)) return false;
        $xmlstr = file_get_contents($xml);
    }else{
        $xmlstr = $xml;
    }
    $result= json_decode(json_encode(simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    return $result;
}  


/**
 * 数组转xml字符
 * @param  string   $xml xml字符串
 **/  
function arrayToXml($data){
    if(!is_array($data) || count($data) <= 0){
        return false;
    }
    $xml = "<xml>";
    foreach ($data as $key=>$val){
        if (is_numeric($val)){
            $xml.="<".$key.">".$val."</".$key.">";
        }else{
            $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
        }
    }
    $xml.="</xml>";
    return $xml;

htmlspecialchars,strip_tags 来过滤html,js 代码

设计模式


__get  __call  abstract 灵活运用实例 编写通用SDK
1.利用__get获取没有定义的变量然后来通过__call调用未知方法
2.abstract 的子类定义的变量 是可以覆盖 父类的定义的变量
3.abstract 里面放子类里面公用的代码

$shopify = PHPShopify\ShopifySDK::config($config);

$products = $shopify->Product->get(['fields'=>'id,images,title']);

public static $config = array(
);
public function __construct($config = array())
{
    if(!empty($config)) {
        ShopifySDK::config($config);
    }
}


public function __get($resourceName)
{
    return $this->$resourceName();
}

    
public function __call($resourceName, $arguments)
{
if (!in_array($resourceName, $this->resources)) {
    if (isset($this->childResources[$resourceName])) {
        $message = "$resourceName is a child resource of " . $this->childResources[$resourceName] . ". Cannot be accessed directly.";
    } else {
        $message = "Invalid resource name $resourceName. Pls check the API Reference to get the appropriate resource name.";
    }
    throw new SdkException($message);
}

    $resourceClassName = __NAMESPACE__ . "\\$resourceName";
    
    //If first argument is provided, it will be considered as the ID of the resource.
    $resourceID = !empty($arguments) ? $arguments[0] : null;
    
    //Initiate the resource object
    $resource = new $resourceClassName($resourceID);
    
    return $resource;
}


abstract class ShopifyResource{
    
       /**
     * @inheritDoc
     */
    public $resourceKey;

    /**
     * @inheritDoc
     */
    protected $childResource;

    public function __construct($id = null, $parentResourceUrl = '')
    {
        $this->id = $id;
    
        $config = ShopifySDK::$config;
    
    }
}

class Product extends ShopifyResource
{
    /**
     * @inheritDoc
     */
    public $resourceKey = 'product';

    /**
     * @inheritDoc
     */
    protected $childResource = array(
        'ProductImage' => 'Image',
        'ProductVariant' => 'Variant',
        'Metafield',
        'Event'
    );
}









<?php
/**
 * 事件产生类
 * Class EventGenerator
 */
abstract class EventGenerator
{
    private $ObServers = [];

    //增加观察者
    public function add(ObServer $ObServer)
    {
        $this->ObServers[] = $ObServer;
    }

    //事件通知
    public function notify()
    {
        foreach ($this->ObServers as $ObServer) {
            $ObServer->update();
        }
    }

}

/**
 * 观察者接口类
 * Interface ObServer
 */
interface ObServer
{
    public function update($event_info = null);
}

/**
 * 观察者1
 */
class ObServer1 implements ObServer
{
    public function update($event_info = null)
    {
        echo "观察者1 收到执行通知 执行完毕!\n";
    }
}

/**
 * 观察者1
 */
class ObServer2 implements ObServer
{
    public function update($event_info = null)
    {
        echo "观察者2 收到执行通知 执行完毕!\n";
    }
}

/**
 * 事件
 * Class Event
 */
class Event extends EventGenerator
{
    /**
     * 触发事件
     */
    public function trigger()
    {
        //通知观察者
        $this->notify();
    }
}

//创建一个事件
$event = new Event();
//为事件增加旁观者
$event->add(new ObServer1());
$event->add(new ObServer2());
//执行事件 通知旁观者
$event->trigger();

Yii框架

多图上传
https://blog.csdn.net/zbc496218/article/details/51442051

值得学习博客: http://www.yiichina.com/extension/1206

中文文档 http://www.yii-china.com/doc/guide/structure_widgets.html
白狼寨

GridView http://blog.csdn.net/myhuashengmi/article/details/53386206

use common\widgets\ImgMultUpload;
<?= ImgMultUpload::widget(['label' => '产品图片', 'imgarr'=>['12321.jpg'],'imagedir' => '/uploads/temp/']); ?>


引入类方法:
①Yii::$classMap['类名']=>'@app/libs/文件名';映射类,在controller中调用
use 类名;可立即使用;此类中不需要写 namespace
②在config数组中加入 aliases=>['@test'=>@app/文件夹];test代表后面的链接,别名引入类。use 别名\类名;可立即使用。  此类中需要写 namespace

打印当前所执行的sql
echo $query->createCommand()->getRawSql();die;

params文件夹中配置写经常变化的内容:  key =>value 形式展示
Yii::$app->param['key']获取参数value值。

composer安装yii框架   安装好之后进入yii框架中进行composer install 安装vendor目录
controller操作注意:
 请求参数:   $request=Yii:$app->request;   $request->get(); $request->post();
             $request->bodyParams();可以获取任何类型以及所有的参数
             $request->getBodyParam('id')特定的获取某个参数
 render    renderPartial不会渲染模板。 
注意事项:
①模型类,需引入use Yii;ActiveRecord类用。

Controller声明需要注意 actionIndex  方法名必须是驼峰式的,action来声明是可以跳转的方法

migrate生成数据库
① 在根目录生成migrations 目录生成对应的文件 yii  migrate/create test
②修改test文件,中间引入 yii\db\Schema,利用Schema来生成表的和结构
③最后使用 yii migrate 来生成对应的数据库。


yii框架中设置别名
在web.php 里面  设置 Yii::setAlias('@bar','www.baidu.com');
                 取出Yii::getAlias('@bar');


gii,debug访问不到,原因可能是继承Controller,默认访问的是r=index,所以导致路由不到。

美化url:  将urlmanager 写到components数组中 (此方法暂时不能正常使用)

'urlManager' => [
    'enablePrettyUrl' => true,  //是否启用美化url pathinfo 模式
    //就必须添加扩展名
    'showScriptName' => false,  //是否显示脚本名
    'rules' => [
    ],
],
使用以上的方法UrlManager控制路由,导致Url::to([]);方法不能正常使用,解决办法:
在入口文件平级目录创建.htaccess 文件,内容如下:
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php


yii-debug

显示在页面中加<?php $this->endBody;?>,将显示xdebug
原理:  yii\web\View 中有 endBody 的触发事件,回去触发bootstarp,注册插件,从而将大量的debug样式加载到页面 上,图标因此出现。

时区显示不正确,在web.config中添加 'timeZone' => 'Asia/Shanghai',


__DIR__ 当前目录 不包含文件名字 dirname(__DIR__) 当前目录的 dir 
例如:E:\project\yii\controllers                 E:\project\yii

__FILE__  当前文件路径  包含文件名字 dirname(__FILE__) 所包含当前文件的文件夹
例如:E:\project\yii\controllers\IndexController.php            E:\project\yii\controllers

配置空页面的跳转方法    web.php中配置的有。
'errorHandler' => [
    'errorAction' => 'site/error',
],


控制器中需要声明下 public function actions()
{
    return [
        'error' => [
            'class' => 'yii\web\ErrorAction',
        ],
    ];
}  
访问的页面不在的话就 跳转到该视图  ,将此封装到基础控制器中减少代码

设置方法返回格式  
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

组件component 
在配置文件component中加 key => 类的命名空间,注册后才用Yii::$app-> key->类中方法。即可实现全局访问的效果。


多数据库链接(判别当前数据库)
/**
 * 设置模型获取数据库链接
 * */
public static function getDb(){
    return Yii::$app->get('db_spkx');
}

google 插件

jsonview 滑词翻译 apizza octotree Infinity wappalyzer gitpod

Infinity 账号 2233850112@qq.com 14adb1

composer

composer config repo.packagist composer https://mirrors.aliyun.com/composer 阿里云源

composer config repo.packagist composer https://packagist.phpcomposer.com composer局部声明源

composer selfupdate 更新phar.

https://github.com/zoujingli/ThinkAdmin 通用后台开发框架

https://github.com/geesondog/rhaphp 结合tp5微信开发

https://demo.fastadmin.net 结合tp5后台快速开发(插件化 收费)

https://tencent.github.io/wepy/ 开发小程序框架


composer 命令大全
https://getcomposer.org/doc/03-cli.md#global-options

常用composer 库

composer require nesbot/carbon 时间间隔

composer require guzzlehttp/guzzle curl 请求

composer require yansongda/pay 微信支付包 riverslei/payment

composer require katzgrau/klogger:dev-master 处理日志类

"phpoffice/phpword": "v0.13.*" 生成word 文件

composer require league/fractal 复杂输出ajax 和restful

composer require phpmailer/phpmailer 邮件处理类

账号 15239851762@163.com 163 测试 发送密码填写 smtp 的授权密码 smallsha666 端口 465

composer require overtrue/easy-sms 短信处理类

https://segmentfault.com/a/1190000007411281 图片处理类

filp/whoops

catfan/medoo

twig/twig

sysfony


composer操作

composer depends ak_smallsha/application -t

获取当前composer中的有关当前包的扩展

composer config --list 查看当前包的配置信息

composer search 包 查询composer中包

composer show aferrandini/* 查询当前项目中的包

composer clear-cache 下载包出现问题首先执行该命令

composer init --require = ak_smallsha/application -n

创建一个新的composer.json包并且添加依赖

可能的少使用comoser update -vvv 导致更新最新版本,项目不兼容。
每次引入类库后,将composer.json和composer.lock 上传到github上。

composer dump-autoload -o 之后,composer
就会提前加载需要的类并提前返回。这样大大减少了 IO 和深层次的 loop。

composer clear-cache 清除缓存

composer install - 如有 composer.lock 文件,直接安装,否则从
composer.json 安装最新扩展包和依赖;

composer update - 从 composer.json 安装最新扩展包和依赖;

composer update vendor/package - 从 composer.json 或者对应包的配置,并更新到最新;

composer require new/package - 添加安装 new/package, 可以指定版本,如: composer require new/package ~2.5.

代码上传到packlist https://www.cnblogs.com/zhangwei595806165/p/5814476.html
http://blog.csdn.net/hel12he/article/details/46659749 在packlist自动更新github上的包

发布自己的composer包

composer是什么
Composer 不是一个包管理器。是的,它涉及 “packages” 和 “libraries”,但它在每个项目的基础上进行管理,在你项目的某个目录中(例如 vendor)进行安装。默认情况下它不会在全局安装任何东西。因此,这仅仅是一个依赖管理。
Composer 受到了 node’s npm 和 ruby’s bundler 的强烈启发。而当时 PHP 下并没有类似的工具。
composer可以做什么
Composer 将这样为你解决问题:
你有一个项目依赖于若干个库。
其中一些库依赖于其他库。
你声明你所依赖的东西。
Composer 会找出哪个版本的包需要安装,并安装它们(将它们下载到你的项目中)。
系统学习composer的使用请移步 composer中文学习
开发自己的composer组件
要点:理解composer如何实现自动加载第三方组件; 理解psr-0和psr-4的规范; 理解基于psr-0,psr-4,classmap,files如何实现自动加载。 理解Composer和Packagist
关于安装和使用composer请参考composer中文学习
创建目录名称
mkdir try-make-package
cd try-make-package
这个try-make-package文件夹就是你的包的根目录了,你只需要记住composer.json在包的哪个目录下面,一般那就是包的根目录了。
现在我们还没有composer.json文件,下面我们来初始化
初始化扩展包
☁  composer init
  Welcome to the Composer config generator
This command will guide you through creating your composer.json config.
Package name (<vendor>/<name>) [lingan/try-make-package]:
Description []: try make a package
Author [saboran <saboran@163.com>, n to skip]:
Minimum Stability []: dev
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: MIT
Define your dependencies.
Would you like to define your dependencies (require) interactively [yes]? n
Would you like to define your dev dependencies (require-dev) interactively [yes]? n
{
    "name": "lingan/try-make-package",
    "description": "try make a package",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "saboran",
            "email": "saboran@163.com"
        }
    ],
    "minimum-stability": "dev",
    "require": {}
}
Do you confirm generation [yes]? yes
经过一番上面的挣扎在当前目录就生成了composer.json文件,下面我们对这个文件进行一些修改
修改composer.json增加自动加载规范(命名空间和目录映射关系)和环境要求
{
  "name": "lingan/try-make-package",
  "description": "try make a package",
  "type": "library",
  "license": "MIT",
  "authors": [
    {
      "name": "saboran",
      "email": "saboran@163.com"
    }
  ],
  "minimum-stability": "dev",
  "require": {
    "php": ">=7.0"
  },
  "autoload": {
    "psr-4": {
      "Flower\\Rose\\": "src/Flower/Rose",
      "Flower\\Lily\\": "src/Flower/Lily"
    }
  }
}
创建类文件
根据上面的命名空间和目录的映射关系,创建对应目录和文件,如下图

对应文件内容
<?php
/**
 * Created by PhpStorm.
 * User: Lingan
 * Date: 2017/11/6
 * Time: 21:39
 */
namespace Flower\Rose;
class Rose
{
    public function desc()
    {
        echo "this is rose flower";
    }
}
<?php
/**
 * Created by PhpStorm.
 * User: Lingan
 * Date: 2017/11/6
 * Time: 21:38
 */
namespace Flower\Lily;
class Lily
{
    public function desc()
    {
        echo "this is lily flower";
    }
}
测试安装
以上代码都梳理完毕后,需要composer install来测试我们的包是否可以正常工作此时会在vendor/composer/autoload_psr4.php中生成命名空间和目录的映射关系,被包在一个数组中:
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
    'Flower\\Rose\\' => array($baseDir . '/src/Flower/Rose'),
    'Flower\\Lily\\' => array($baseDir . '/src/Flower/Lily'),
);
增加.gitignore为git忽略一些文件,增加readme.md为项目增加描述
.idea
vendor/
composer.lock
提交代码到github
现在自己的Github主页上创建一个新的仓库然后将项目提交到对应仓库,参考如下
git init
git add -A
git commit -am "init && dev package"
git remote add origin git@github.com:linganmin/try-make-package.git
git push -u origin master

登录自己的packagist submit(自己注册)
将自己的项目地址粘贴


点击check,然后点击submit,至此,自己的composer包就提交成功了,

测试使用自己开发的包扩展[2017.11.07更新]
创建测试目录
mkdir test-my-package
cd test-my-package
安装自己的扩展
 composer require lingan/try-make-package dev-master
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing lingan/try-make-package (dev-master d7b9f94): Cloning d7b9f941b0 from cache
Writing lock file
Generating autoload files
安装完成的目录如下图

查看autoload_psr4.php
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
    'Flower\\Rose\\' => array($vendorDir . '/lingan/try-make-package/src/Flower/Rose'),
    'Flower\\Lily\\' => array($vendorDir . '/lingan/try-make-package/src/Flower/Lily'),
);
新建首页入口文件index.php,开始测试自己写的包
<?php
/**
 * Created by PhpStorm.
 * User: Lingan
 * Date: 2017/11/7
 * Time: 11:04
 */
require_once './vendor/autoload.php'; // 加载自动加载文件
use Flower\Rose\Rose;
use Flower\Lily\Lily;
$rose = new Rose();
$lily = new Lily();
echo $rose->desc();
echo "\n";
echo $lily->desc();
执行
php index.php
this is rose flower
this is lily flower%
* 至此说明我们自己开发的扩展包可以正常使用
设置Packagist上自动更新扩展包,即当我们更新扩展包提交到GitHub时,Packagist自动更新
在没有设置自动更新时,Packagist上包详情页会有这样一个提示
This package is not auto-updated. Please set up the GitHub Service Hook for Packagist so that it gets updated whenever you push!(这个软件包不是自动更新的。请为Packagist 设置GitHub服务钩,以便在您推送时更新!)
详细设置自动更新软件包的文档地址
简化步骤如下:
去个人中心页面拿到自己的api令牌
去当前包在GitHub的地址,点击设置,点击集成和服务,点击添加Packagist服务并配置你的API令牌,以及你的Packagist用户名和账号对应域名
选择active,点击add service
设置自动更新结束,之后你更改了自己包扩展的代码提交到GitHub后,很短的时间差就会同步到Packagist

laravel

http://laravel-admin.org/ laravel-admin

https://www.jianshu.com/p/18d3b77a13f3

数据库迁移
http://laravelacademy.org/post/130.html

数据库操作
http://laravelacademy.org/post/8060.html

http://blog.csdn.net/ks3ks/article/details/54942816

权限RBAC
https://packagist.org/packages/zizaco/entrust#dev-master

分页
http://laravelacademy.org/post/8156.html

项目
https://www.bandari.net/blog laravel整合workerman

队列
http://blog.csdn.net/chen529834149/article/details/78894894

核心一   Facade   
 方便开发者直接用静态方法调用,加快开发速度,不需要依托服务器容器。
创建 facade  步骤 1 先写好自己的方法  
 步骤2  编写providers 可以使用  php artisan make:provider 生成服务提供者
public function register()
{
将写好的方法注册到 ajaxResponse;
    $this->app->singleton('ajaxResponse', function () {
        return new \App\Services\ajaxResponse();
    });
}

步骤3 编写 facades 
class AjaxResponseFacade extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'ajaxResponse';
    }
}

步骤4 进入config/app.config

在providers 数组中编写  将服务提供者provides ::class 注册进去

步骤5 
在aliases 中将编写好的门面 放入。方便调用。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

核心二  服务器容器
服务容器      使用命名空间引入类,然后将名称注入到 __construct或者是方法名中,声明变量,将注入的类指定到变量中,此方法雷同于yii框架的组件化。


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

核心三  contracts  契约     主要是减少代码的冗余

①首先编写一个接口contracts 接口类
②在编写自己的要实现功能 implement 继承接口类
③开始编写provider ,实现register方法
public function register()
{
    //给这个接口一个别名
    $this->app->bind('Hello','App\Contracts\Hello');
    //将Contract接口和它的实现类绑定
    $this->app->bind
    ('App\Contracts\Hello','App\Services\helloWorld');

}
④然后将此provider放入到config\app.php中
⑤在类中调用使用服务容器的方法进行调用

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

laravel 文档
博客 http://www.cnblogs.com/itfenqing/category/1010078.html
小下博客    https://www.linganmin.com/show/59
韩天峰博客  http://rango.swoole.com/archives/519
laravle中文手册:http://d.laravel-china.org/docs/5.4     速查: https://cs.laravel-china.org/
http://laravelacademy.org/post/7930.html   smartApi 项目
https://github.com/JJJJJJJerk/laravel-passport-admin-stock-loan   laravel5.5 
=====================================================================
常用 artisan命令   

php artisan make:controller PhotoController --resource --model=Photo 
php artisan make:model User -m   生成模型并生成迁移文件
=====================================================================
常用blade
{!! $name !!} 防止xss 攻击
{{ $name or $hello }}  三元运算符



=====================================================================

常用组件
laravel-password oauth2认证 
https://www.jianshu.com/p/2988ba405b3b?from=timeline&isappinstalled=0

easywechat 网页授权
https://github.com/overtrue/laravel-wechat
https://github.com/overtrue
微信机器人 swoole
http://create.hanc.cc/vbot/docs/install.html

laravel-debugbar  监控sql和route
http://laravelacademy.org/post/2774.html   
默认会将debugbar 添加到页面的body后, 
\Debugbar::disable(); 关闭
 \Debugbar::enable();开启
config 里面inject  设置false 禁止渲染页面
==================================================================
常见问题
base类中获取不到session,原因
在Laravel以前的版本中,可以在控制器构造函数中获取session变量或者认证后的用户实例。 
在Laravel 5.3中,在控制器构造函数中不再能够直接获取到session变量或认证后的用户实例,因为中间件还未启动。 
仍然有替代方案,那就是在控制器构造函数中使用Closure来直接定义中间件。 
请注意,在使用这个方案的时候,确保你所使用的Laravel版本高于 5.3.4:
可以在构造方法中采用以下方法获取:
$this->middleware(function ($request, $next) {
    return $next($request);
});
base64 数据流图片解决办法
$base64_string= explode(',', $base64_string); //截取data:image/png;base64, 这个逗号后的字符
$data= base64_decode($base64_string[1]);  //对截取后的字符使用base64_decode进行解码
file_put_contents($url, $data); //写入文件并保存

https://www.cnblogs.com/lyzg/p/6181055.html   app()使用
https://www.onmpw.com/tm/xwzj/sjk_251.html   mysql 查询判断
https://segmentfault.com/q/1010000009858793   422 ajax处理
用户管理系统  php artisan  make:auth  -> php arisan migrate出现数据unique字节数过大,原因laravel 采用utf8mb4 字符,mysql 默认是utf-8. 处理方法在app->provides->appprovide->boot方法下加入    use Illuminate\Support\Facades\Schema;          Schema::defaultStringLength(191);

php artisan vendor:publish  --provider   命令迷惑 

swoole

swoole 博客 包含mac 快捷软件
https://www.cnblogs.com/redirect/p/7837238.html

swoole 配置说明
https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/01.swoole_server%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9.md

守护进程开启后,关闭采用
http://blog.csdn.net/qq_33679504/article/details/78659220

swoole 成员博客
https://blog.csdn.net/u012979009/article/details/54602935

pecl 安装swoole 出现sll
https://stackoverflow.com/questions/31842400/ssl-issue-after-pear-channel-update-pear-php-net

//nginx 设置第一发包和第二次发包 时间等待
https://blog.csdn.net/jack______/article/details/76588998

websocket客户端断开状态码
https://www.javascriptcn.com/read-30780.html

注意事项

查看php.ini 位置 php -i|grep php.ini  
查看是否含有swoole.so  cat /www/server/php/71/etc/php.ini| grep swoole.so

swoole_websocket_server     php  --ri swoole查看php是否支持swoole
服务器端绑定ip  0.0.0.0  端口需要注意将阿里云的安全策略打开
客户端绑定ip  39.106.59.83 端口号和服务器端绑定端口号一致

①代码中不要使用sleep,导致进程堵塞
②exit/die,导致woker进程退出
③register_shutdown_function  来捕获致命错误
④在回调函数中使用try/catch,否则程序异常,不支持set_exception_handler
⑤连接redis,mysql类型的连接应该放到OnWorkerStart 回调函数中
⑥引入文件 使用include_once,require_once;
⑦worker是隔离的,使用swoole_table 将全局变量保存起来。
⑧事件回调中所有的局部变量都会全部回收,全局变量需要自己unset
⑨global,static,$_GET,$_POST,$GLOBALS 保存在swoole_server 不会自动释放
⑩多进程的情况下,父进程使用mt_rand,子进程要使用mt_srand。

server 配置
dispatch_mode = 7  无论极端条件下任务都会及时处理

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容