大话转岗PHP开发小结

image

前言

近期因公司内部转岗,开始参与PHP项目进行后端开发,一直都是强类型写的比较多,弱类型语言也有接触了一些,如:nodejs,python,作一些辅助服务,数据采集的事情,恰好内部有这个机会进行能够学以至用,加上以前对后端的理解和经验,很容易上手,这里记录下开发过程遇到的些问题解决方案和本身对PHP的理解,以及项目中的部分架构php

当前已经进入PHP7的版本,作了不少的调整,尤为在性能上有很大的提高html

面向对象

image

PHP框架内置不少强大函数,超级全局变量,魔术函数,魔术变量,能够经过提供的内置函数对PHP项目进行拓展,数据类型操做,http信息获取等,经过安装拓展添加各类功能支持,框架内置函数调用大部分仍是偏向面向过程,经过调用函数,传入要操做的类型数据和依赖数据,这里刚开始有些不习惯,面向对象的开发中习惯直接 类型变量/对象 点出函数。java

如今PHP开发能够选择使用面向过程也能够用面向对象,最先PHP版本不支持面向对象特性,PHP5开始对OOP有良好的支持,不少PHP开发者没有系统性的学习OOP相关知识,包括工龄长的PHP开发者或者老的项目不少仍是偏向面向过程开发,因此会接触到不少偏向面向过程开发的项目node

在项目开发过程当中遇到些偏应用业务开发的项目,看似有用到类,可是并没用到面向对象的特性对业务进行抽象,如:项目中每一个业务功能有个php文件对应一个类,类里里大部分都是逻辑function,而后经过拓展autoload,实现自动include php文件,好比经过L函数传入要调用的类名,构造出PHP文件路径,进行include,而后返回类实例对象,只是经过类文件来区分功能函数,并无使用到面向对象的特性进行封装,仍是偏向面向过程思路在开发python

PHP5开始对OOP提供了良好支持,基本已经和java,C# 面向对象语法类似,可使用命名空间,封装interface,abstract,多态:implements,extends,PHP7还支持多继承trait,方便封装些公用的功能,经过PSR4规范,引入composer 实现的autoload,能够很好的进行OOP开发mysql

PHP开发仍是比较灵活,能够面向过程也能够面向对象,根据具体的业务场景设计nginx

使用composer psr4git

  • 在项目中添加composer.json文件,根据本身需求配置
{
  "autoload": {
    "psr-4": {
      "Library\\": "library/"
    }
  }
}
  • 在composer.json文件所在目录下输入命令,就会自动 download vendor/composer autoload 相关文件
composer install
  • php中的入口index include autoload.php
include_once "vendor/autoload.php";
  • 注意,配置修改,内容变动的时候须要执行
composer dump-autoload -o

弱类型问题

编码问题:

在刚学习PHP语法的时候比较不习惯的就是弱类型,不用去定义变量类型,参数类型,返回值类型,对于习惯强类型的童鞋开始会有些不习惯,不定义类型内心怪怪的,总感受哪里会致使些错误,并且弱类型在编码的过程当中IDE不会有类型错误的一些提示,只有在运行的时候报错了才能知道这里错误了,错误提示滞后。尤为是从DB查询数据返回的是一个stdclass/array,获取到的数据没有对应一个实体类,没法知道具体数据有哪些字段,须要经过查询的sql语句,而后经过查看表结构才能知道数据字段信息,这点很难受,影响开发效率github

PHP如今已经支持typehint,经过定义类型能够对部分肯定的类型变量,参数,返回类型进行强类型的定义,尤为须要定义表数据Model类,这样获得数据对象后经过->能够感知出全部数据字段,方便后续拓展开发和维护web

根据场景使用,不能说由于本身习惯使用强力型就把全部类型定义都写成强类型

/**
 * Class MJop
 * @property int $id 工做ID
 * @property string $name 工做名字
 * @property int $salary 薪水
 */
class MJop
{
}

/**
 * Class MWorker
 * @property string $name 员工名字
 * @property int $age 年龄
 * @property MJop $jop 工做
 */
class MWorker
{
}

class Worker
{
    /**
     * 获取员工信息
     * @param int $id
     * @return MWorker|stdClass
     */
    public function get(int $id): stdClass
    {
        // mysql select
        return new stdClass();
    }
}

class Logic
{
    /**
     * 获取员工描述
     * @param int $workId
     * @return string
     */
    public function Desc(int $workId): string
    {
        $worker = new Worker();
        $mWorker = $worker->get($workId);
        return '名字:' . $mWorker->name . ',年龄:' . $mWorker->age . ',工做:' + $mWorker->jop->name . ',薪水:' . $mWorker->jop->salary;
    }
}

经过定义变量类型获得代码感知

/** @var Logic $logic */
$logic=new Logic();
弱类型比较一个头两个大:

由于PHP是弱类型缘由,在作类型比较的时候,每每会由于一个不当心就掉坑里,下面列出类型函数和类型比较的表格

就问你,看到这些表格怕不怕,心中有一万只草泥马奔腾而过,瞬间变成幽怨的小眼神

image

使用 PHP 函数对变量 $x 进行比较

表达式 gettype() empty() is_null() isset() boolean : if($x)
$x = ""; string TRUE FALSE TRUE FALSE
$x = null; NULL TRUE TRUE FALSE FALSE
var $x; NULL TRUE TRUE FALSE FALSE
$x is undefined NULL TRUE TRUE FALSE FALSE
$x = array(); array TRUE FALSE TRUE FALSE
$x = false; boolean TRUE FALSE TRUE FALSE
$x = true; boolean FALSE FALSE TRUE TRUE
$x = 1; integer FALSE FALSE TRUE TRUE
$x = 42; integer FALSE FALSE TRUE TRUE
$x = 0; integer TRUE FALSE TRUE FALSE
$x = -1; integer FALSE FALSE TRUE TRUE
$x = "1"; string FALSE FALSE TRUE TRUE
$x = "0"; string TRUE FALSE TRUE FALSE
$x = "-1"; string FALSE FALSE TRUE TRUE
$x = "php"; string FALSE FALSE TRUE TRUE
$x = "true"; string FALSE FALSE TRUE TRUE
$x = "false"; string FALSE FALSE TRUE TRUE

松散比较 ==

类型 TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "php" ""
TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE FALSE FALSE TRUE FALSE
FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE TRUE FALSE TRUE
1 TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
0 FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE FALSE TRUE TRUE
-1 TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
"1" TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
"0" FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
"-1" TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
NULL FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE TRUE FALSE TRUE
array() FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE
"php" TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
"" FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE

严格比较 ===

类型 TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "php" ""
TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
1 FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
0 FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
-1 FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
"1" FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
"0" FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
"-1" FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
NULL FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
array() FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
"php" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
"" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE

刚接触PHP看到这几个表格的时候会有点儿晕,开发的时候须要特别注意下类型比较,对等比较尽可能用'===',一些函数类型已经可以肯定不会传递多类型参数,就能够强制类型进行限制,后面熟练度上来再看这个表格就感受也还好,经常使用的类型之间的比较已经深深的进入到脑海中

其余问题:
  • IDE没办法给定义的变量进行错误提示,由于没有定义类型IDE也不清楚定义变量的类型,没办法作错误提醒,每每须要在运行的时候输出到页面上才能发现问题
  • PHP弱类型引起的漏洞实例

PHP灵活性

上面说了这么多弱类型下的问题,这里说下弱类型的优势,弱类型一个明显的优点就是灵活
PHP动态特性,能够动态实例化,动态添加属性,动态调用函数,等,经过这些特性能够用简单的代码封装出强大的功能

image

简单举栗子:

<?php

class Developer
{
    public $name;
    public $hair;

    /**
     * 介绍
     */
    public function introduce()
    {
        $desc = '名字:' . $this->name . ',发量:' . $this->hair;
        if (!empty($this->age)) $desc = $desc . ',年龄:' . $this->age;
        echo $desc . "\r\n";
    }

    /**
     * 数据逻辑处理
     * @param $condition
     * @return bool|string
     */
    public function handle($condition)
    {
        if (is_int($condition)) {
            // ... ... 逻辑
            return '数字处理结果';
        } else if (is_string($condition)) {
            // ... ... 逻辑
            return '字符串处理结果';
        } else if (is_array($condition)) {
            // ... ... 逻辑
            return '数组处理结果';
        } else {
            return false;
        }
    }
}

// -----动态添加对象属性-----
$xm = new Developer();
$xm->name = '码圣';
$xm->hair = 80;

// 方式1 - 变量做为属性名
// $fieldAge = 'age';
// $developer->$fieldAge = 20;

// 方式2 - 直接设置属性值
$xm->age = 20;


// -----动态调用对象函数-----

// 变量做为函数名调用
$fn = 'introduce';
if (method_exists($xm, $fn)) $xm->$fn();


// -----动态实例化-----

// 方式1 - 变量做为类名进行实例化
$className = 'Developer';

/** @var Developer $xf */
$xf = new $className();
$xf->name = '小方';
$xf->hair = 30;
$xf->introduce();


// ------属性遍历------
foreach ($xf as $key => $val) {
    echo $key . '=' . $val . "\r\n";
}


// ------参数类型和返回值支持多类型------

$rs = $xf->handle(null);
if ($rs === false) {
    echo '处理失败';
} else {
    echo $rs;
}

// ------函数变量------

$fn = function () {
    echo 'do something';
};

$fn();

独特特性

内存不常驻

PHP WEB服务端开发,服务器部署多依赖fastcgi进程管理器,static变量和C#包括java生命周期不同,C#/java 的WEB应用服务进程静态变量是常驻在内存里而且共享,PHP大多使用nginx部署fastcgi进程管理,服务器接收请求的进程是彼此独立的,请求响应完了就回收资源,不存在常驻。

固然PHP也是能够内存常驻的,cli(命令行模式)下内存是常驻,swoole框架开发部署的WEB应用服务也是内存常驻

错误级别

以往在C#开发的时候,执行遇到错误会直接抛出异常,try catch 能够捕获错误异常,出现异常不会继续执行后面的内容,PHP会比较不同,根据不一样的错误级别不同的执行机制

PHP 有几个错误严重性等级。三个最多见的的信息类型是错误(error)、通知(notice)和警告(warning)。它们有不一样的严重性: E_ERROR、E_NOTICE和E_WARNING。错误是运行期间的严重问题,一般是由于代码出错而形成,必需要修正它,不然会使 PHP中止执行。通知是建议性质的信息,是由于程序代码在执行期有可能形成问题,但程序不会中止。 警告是非致命错误,程序执行也不会所以而停止。

PHP 能够控制错误是否在屏幕上显示(开发时比较有用)或隐藏记录日志(适用于正式环境) 更改错误报告行为:

# 方式1:配置php.ini
error_reporting=E_ALL &  ~E_NOTICE
//方式2:函数调用设置报错级别
error_reporting(E_ALL & ~E_NOTICE);

行内错误抑制: 错误控制操做符 @ 来抑制特定的错误。将这个操做符放置在表达式以前,其后的任何错误都不会出现。

<?php echo @$var['sflyq'];

php的Error与Exception捕获问题:

Error是检测到的这个问题极有可能使程序没法继续运行,而Exception则是虽然有问题可是程序继续运行不受影响。在php7之前的版本中Error类型是不能被捕获的,仅仅能够捕获Exception类型。php7之后Error与Exception都继承了Throwable接口,使得Error被捕获成为可能,在php7如下的版本也能够捕获Error

  • register_shutdown_function 注册一个 callback ,它会在脚本执行完成或者 exit() 后被调用。
  • set_error_handler 本身定义的方式来处理运行中的错误
  • set_exception_handler 设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常
链接池

涉及数据库开发过程当中通常都会用到链接池,经过使用链接池减小每次须要从新创建链接的时间消耗提升数据操做效率,在高并发业务场景下效果尤其明显,由于目前大部分PHP应用服务都是使用fastcgi的进程管理,每一个请求服务器会分配进程去处理,返回结果后进程资源就会自动回收,由于这个因素没法创建链接池

方式1:
fastcgi模式下目前比较合理的方式就是经过单例模式,保证在当前请求操做下的数据链接只建立一个对象

方式2:
能够经过swoole拓展实现数据链接池服务,传递sql到服务里执行返回数据,swoole内存常驻,应用客户端链接断开链接池服务进程资源不会自动回收


多线程 协程

多线程

线程(thread) 是操做系统可以进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运做单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中能够并发多个线程,每条线程并行执行不一样的任务

  • pthread扩展
    • 适用于cli
    • 单独配置php-cli.ini
  • swoole
    • 是一个底层网络库
  • gearman
    • 实现了一个 Master-Worker 的模型
    • 分布式任务分发
    • 教程
  • workerman
    • php 实现的一个网络库
协程

线程是由操做系统内核进行调度的,咱们没法干预,协程是用户态程序,至关于应用程序本身进行了调度。

由于它是用户态程序,因此至关于多个协程会运行在一个线程中。

要注意的是,只有内核对线程的调度才可以利用cpu的多核资源,让程序作到并行,因此在一个线程中的多个协程,是没法作到并行的。

用户态和内核态:
简单一句话,程序执行时,若是执行的是咱们编写的应用程序的代码,这些代码就是运行在用户态的;当代码中调用了系统调用后,接下来内核中的代码就会执行,内核中的代码就是运行在内核态的

  • swoole 4.0 全新的协程内核

应用服务器架构

服务部署:

  • php7+nginx+php-fpm
  • gitlab代码托管,自动发布环境
  • ELK日志服务
    • Elasticsearch 搜索引擎
    • Logstash/Filebeat 用户日志处理
    • Kibana 用于对存储在Elasticsearch里的结构化数据作可视化展示
  • mysql
    • 根据业务分布式集群
  • redis
    • codis 分布式部署
  • mongodb
  • kafaka
    • 日志记录,BI处理

代码托管和测试环境:

均使用阿里云服务器,代码托管自建gitlab服务,从开发分支合并到gitlab环境分支自动部署到对应环境服务器上

  • 测试环境
    • test-app.sflyq.com
    • 测试数据库
    • 公司内网访问
    • gitlab release
  • 预发环境
    • yf-app.sflyq.com
    • 生产数据库
    • 公司内网访问
    • gitlab simulation
  • 生产环境
    • app.sflyq.com
    • gitlab master
  • 本地测试环境
    • 经过docker部署

最近阶段感悟

image

从一个熟悉的语言到另外一个相对陌生的语言,语言只是工具,在适合的场景下使用适合的工具,从本身熟悉的业务到陌生的业务,离开本身的舒服区,拥抱变化才能成长

在相同的后端领域切换语言学习成本仍是比较低的,主要是对后端开发的思路,经验是能够共用的,只是换了个语言去实现

当公司发展到必定的规模,岗位职能区分的很细,作应用开发的童鞋接触不到服务器架构,没有机会接触职能之外的技术,工做内容除了完成业务需求开发,仍是业务需求开发,这样常年开发下去对我的成长的局限性很高,须要本身在工做之余进行拓展,对公司内部有兴趣的技术进行了解和学习,耐心等待机会的到来

在结尾重点说下做为开发应该有的工做态度,感受大部分开发参与项目广泛责任感和带入感不强,需求过来没有多想,pa pa pa就是一梭子代码,按照产品的逻辑流程码了整个业务功能,功能测试上线能够正常运行没有问题,而后功成身退,两耳不闻天下事,做为开发在参与项目把本身摆在什么样的位置决定这你是什么样的工做态度

从项目角度出发应该把本身全部参与的项目当成本身的孩子,须要主动关注和关心项目的数据状况和后续发展,伴随着孩子成长了,慢慢就有了成就感

从技术角度出发须要把项目需求功能开发当成造房子,须要分析业务需求提供合理的设计方案,适当的抽象和使用设计模式,只有在开发的时候把地基打稳了才能保证后续的维护和拓展,避免技术债

image

2019年开年第一篇,祝你们和本身新的一年里猪事顺利,大吉大利!

欢迎Star 【大话WEB开发】

相关文章
相关标签/搜索