【本文为个人意见,不喜就喷吧!】

最近,同事问到我,『那时候为什么从PHP转成Java?』,我想了很久,且撇开主观上的原因,当初业务重构使用java确实有很多可以说道的地方。

槽点1:哪有最好的语言,只有最合适的语言

2017年的3月份,我所维护的业务,跑的是php,使用的是thinkphp3.2 框架。刚接手的时候,这个业务还是单机,还记得有同事笑道:『这台机厉害哈,单机一年能跑出200多万的流水来!』我当然是一笑置之。可是随着业务组扩展外部渠道,开始发展这个业务,我慢慢发现这样子的系统很难搞:难维护,难扩展,难自定义,不稳定。这样子的系统,每次改到支付功能,上线都是心虚的,就怕突然出现问题,影响用户体验。于是在一段煎熬的思索和过渡后,老大开始带着我进行重构。最开始的一套方案,是准备放弃原有的tp 框架,转而使用 yii2,但由于人手不够,老大亲自操刀,架起了一套 play1.4.3(业务端) + spring-mvc(后台管理) 的一套系统,所以,我也转到了java。

我这里想说的是,一个项目选择啥语言,需要考虑团队的配置,不能上来就搞一套不切实际的东西,从实际出发,找到适合自己的语言。曾几何时,我也觉得php是世界上最好的语言,还没有之一,现在只觉得哪有最好的语言,只有最合适的语言。

......

槽点2:面向对象编程,而不是面向数组编程

也许你一定很想知道,如何才能完成从php 到 java 的转身呢?

说实话,一开始的时候,确实很痛苦,基础薄弱就不说了,精神上还有压力,因为全世界都知道【你是写java的 php程序员】。举个特别糗的例子,刚刚写spring-mvc 的时候,不知道如何接收10多个参数,于是我很活该的使用了map, 我当时想啊,这不就是我们php 的 $_GET 和 $_POST 么【想当然害死人呀!】。可是写着写着我就发现不妥了,首先,别人并不知道你的map里面有啥子参数;然后,从map取出来的值不一定有值,如果是null,还要做逻辑判断,这样子代码又麻烦了。所以呀,虽然这个代码顺利上线了,也没发生过大的故障,但是我一直把这份代码当成我的【眼中钉,肉中刺】。后面我是知道了,其实用一个对象来接收这些参数,既优雅,有便于维护,可读性也好。

下面,我把自己最恨的一段代码贴出来,告诫小伙伴们,【别这样子干啊】

   // 控制器 
  @RequestMapping(value = "/list", method = RequestMethod.GET)
@ResponseBody
public AjaxResponse getOrderList(@RequestParam Map<String, String> searchMap) {
return orderService.getListsData(searchMap);
}

  

 // 恶心的逻辑
  /**
* 解析搜索关键词, 组装matches
*
* @param matches
* @param searchKey
* @param searchVal
* @return
*/
public Matches getMatchesBySearchMapEntry(Matches matches, String searchKey, String searchVal) {
switch (searchKey) { case Properties.tradeType:
if (Integer.parseInt(searchVal) > 0) {
matches.eq(Columns.tradeType, searchVal);
}
break;
case Properties.state:
int state = Integer.parseInt(searchVal);
if (state == 4) {
matches.match("complete_status", 1); // 表示已完成
} else if (state == 3) {
matches.match("order_status", 0); // 0 表示已下单
} else if (state == 1) {
matches.match("order_status", 1); // 1 表示已支付
} else if (state == 2) {
matches.match("order_status", 2); // 2 表示已退款
}
break;
case Properties.channelId: List<Long> belongIds = accountService.getChannelIdBelongThisUser(HttpSessionUtils.getUseAccountId());
if (belongIds == null) {
if (GeneralUtil.isObjNotZero(searchVal)) {
matches.match("channel_id", searchVal);
}
} else if (belongIds.size() > 0) {
Long id = Long.parseLong(searchVal);
if (belongIds.contains(id)) {
matches.match("channel_id", id);
} else {
matches.match("channel_id", belongIds);
}
}
break;
case Properties.cepingId:
if (GeneralUtil.isObjNotZero(searchVal)) { List<Long> cepingIds = scalePoolDao.findIdsByParentId(Long.parseLong(searchVal));
matches.match("ceping_id", cepingIds); }
break;
case Properties.orderNo:
matches.match("order_no", searchVal);
break;
case Properties.openId:
String userKey = userDao.getUserKeyByOpenidAndUserType(searchVal, 1);
matches.match("user_key", userKey);
break;
case Properties.userKey:
matches.match("user_key", searchVal);
break;
case Properties.createStartTime: // 下单时间
Date createStartTime = DateTimeHelper.timeFormatStringToDate(searchVal);
matches.gte("create_time", createStartTime);
break;
case Properties.createEndTime:
Date createEndTime = DateTimeHelper.timeFormatStringToDate(searchVal);
matches.lte("create_time", createEndTime);
break;
case Properties.payStartTime: // 支付时间
Date payStartTime = DateTimeHelper.timeFormatStringToDate(searchVal);
matches.gte("pay_time", payStartTime);
break;
case Properties.payEndTime:
Date payEndTime = DateTimeHelper.timeFormatStringToDate(searchVal);
matches.lte("pay_time", payEndTime);
break;
case Properties.userType:
int userType = Integer.parseInt(searchVal);
if (userType > 0) {
matches.eq(Columns.userType, searchVal);
}
break;
case Properties.buyType:
int buyType = Integer.valueOf(searchVal);
if (buyType > 0) {
if (buyType == BuyType.DEFAULT_COPY_ORDER.getCode()) {
buyType = 0;
}
matches.eq(Columns.buyType, buyType);
} break; }
return matches;
}

  

我现在用又臭又长来形容,这样子的code 既不方便阅读,出问题了也不好排查。而且这个代码,我还是放在个循环中来拼接的,可读性之烂可想而知。唉,要是我如果有时间了,就把这段代码改了。

其实呢,说了这么多,我就想说,包括我在内的部分 phper额,太过分依赖数组了。是啊,在php里面,没有啥是一个数组搞不定的,如果有,那就俩个。我走心看了下其它业务线的php代码,哎哟喂,好家伙。推送服务配置用数组,微信公众号配置用数组,接受请求用数组,传参用数组(个人最不喜欢的方式),好像数组少些,项目就不能正常运行了。

我并不是说不该用数组,但是数组确实不好维护。当我们思绪乱的时候,你根本记不清这个数组中有哪些参数,你也可能想不起这个return的对象有哪些对象,特别是return json的时候,如果一个数组不存在,这时候返回了null,这样子返回的接口数据,对客户端的同学来说就是一种灾难。

槽点3:一包不扫,何以扫天下

除此之外,也是我最想吐槽的一点,就是php的命名空间和包管理。虽然php现在也有了composer,但是部分包载入时,还是需要做一下手动处理的,如果是一些小白的话,那久很尴尬了。相对于php呢,java就很成熟了,maven 一出,问题基本就解决了。而php的命名空间呢,我最不爽的一点是,明明一个包没关联上,项目居然还若无其事的走着,之前没觉得咋样,写java后就觉得,这样子特别不严谨,对于我这样的强迫症者来说,不能接受!

还有就是,需要手动载入 扩展,关于这点,php做的不够好

槽点4:定时任务 

此外呢,php有一点做的不够好的,定时任务!(且不说用swoole做定时任务哈,毕竟swoole还是需要点学习成本的呢!)

之前我很少用php做定时任务,如果要做的话,就要依赖linux系统crontab,或者用swoole 了。

但是在java里面,完全不是这样子的体验,在play 或者 spring-mvc ,完全就是一个job 就搞定了,哪里要这般麻烦!

槽点 5:必不可少的单元测试

然后呢,php 在单元测试方面比java 差挺多的。这里我不否认有idea 的功能,但是想要用phpunit 测试一个方法,我感觉千难万难,但是在java里,很容易就实现了!除此之外,包括我在内的部分phper,很少写单元测试,甚至有些压根就不知道这是咋回事!我觉得这是个可怕的现象,这样子的代码,连自己这关都没过,如何敢上线,如何能稳呢!基本上走过单元测试的代码,基本不存在啥语法错误,这就是妥妥的保障啊!

槽点6:你debug都不用,就不要假装在搬砖了

接下来, 包括我在内的部分phper 呢,很少去debug,有些甚至从来没这么搞过。在那段维护 thinkphp的时间了,我开始使用phpstrom的debug,说实话,代码质量,开发效率都有很大的提升!我实在不能再接受自己用 echo, var_dump 这样子去调试代码,这样子会让人觉得,这是个门外汉呢!

槽点7:php是世界上最好的语言

请放下这个想法,你会发现,无论是python,golang,java 都不比咱php差,你不知,只因你未接触!

槽点8:php代码打包功能弱

在写java前呢,每次遇到要复用的php代码呢,我都是直接copy,但是写java 一段时间后,我就觉得java 这方面比较好了,我可以通过maven 对共用的包进行打包,放到另一个项目中去,这样子既方便管理,又利于版本的迭代,省时省力!

好了,就到这里吧,接下来还会有一篇吐槽java的。

PHP/JAVA 杂谈 一(php 槽点)的更多相关文章

  1. Java杂谈6——Java安全模型

    Java语言安全模型是其有别于传统的编程语言的一个很重要的特点,采用一种沙箱模型隔离了Java的运行环境与具体的操作系统,使得Java在网络环境下能够更为安全的运行.理解Java的安全模型,能够帮助我 ...

  2. Java杂谈5——关键字final与volatile

    Final关键字 在Java语言中,随着语境的不同final关键字所代表的语义会有一些细微的差异.总的来说,final关键字表达的含义是“禁止修改”,这层有点类似于C++中的const关键字.之所以要 ...

  3. Java杂谈4——Java中的字符串存储

    Java中的String Java.Lang.String是Java语言自带的字符串实现,它并不是java的基本类型,但却和几乎每个java程序都密切相关的一个基础java类. string类内部实际 ...

  4. Java杂谈3——类加载机制与初始化顺序

    Java语言的哲学:一切都是对象.对于Java虚拟机而言,一个普通的Java类同样是一个对象,那如果是对象,必然有它的初始化过程.一个类在JVM中被实例化成一个对象,需要经历三个过程:加载.链接和初始 ...

  5. Java杂谈2——引用与跟搜索算法

    Java中的引用 Java“引用”的概念源于C++,原本的定义相当有限:一个引用(Reference)代表的内存通常用于指向另一块内存区域的起始地址.通过引用类型保存的起始地址,可以找到这个引用所指向 ...

  6. Java杂谈1——虚拟机内存管理与对象访问

    1.理解JAVA虚拟机的内存管理 运行时的数据区 从java虚拟机的内存分配来看,一个java程序运行时包含了如下几个数据区: a)     程序计数寄存器(Program Counter Regis ...

  7. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  8. java游戏开发杂谈 - 游戏物体

    现实生活中,有很多物体,每个物体的长相.行为都不同. 物体存在于不同的空间内,它只在这个空间内发生作用. 物体没用了,空间就把它剔除,不然既占地方,又需要花精力管理. 需要它的时候,就把它造出来,不需 ...

  9. java游戏开发杂谈 - 有限状态机

    在不同的阶段,游戏所运行的逻辑.所显示的界面,都是不同的. 以五子棋举例,游戏开始.游戏中.胜负已分,对应的界面和逻辑都不同. 在游戏中,又分为:自己下棋.对方下棋.游戏暂停.悔棋等多个状态. 再比如 ...

随机推荐

  1. Android Stdio 中的Rendering Problems Android N requires the IDE to be running with Java 1.8 or later Install a supported JDK解决办法

    出现如下图所示的错误 解决办法为: 然后在里面输入SDK 下载 下载APILevel为23版本的SDK 换成23版本的SDK 完美解决问题

  2. Ubuntu忘记root密码怎么办?

    http://www.linuxidc.com/Linux/2016-05/131256.htm

  3. OSI网络模型

    OSI中的层 功能 TCP/IP协议族 应用层         文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 表示层         数 ...

  4. API token for Github

    1.如图所示:(前提是登录Github,进入Personal settings) 2,创建token 3,生成token 4. Last login: Mon Dec  5 20:24:18 on c ...

  5. 计蒜客 无脑博士 bfs

    题目链接无脑博士的试管们 思路:直接模拟倒水过程即可,但是需要记忆判断当前的情况是否已经处理过.dfs和bfs都ok AC代码 #include <cstdio> #include < ...

  6. LRUCache原理分析

    一.注释 LRUCache的原理,基本都在注释里面描述清楚了. /** * A cache that holds strong references to a limited number of va ...

  7. Docker系统七:Docker数据管理

    Docker的数据管理 I. 基本概念 Docker容器一旦删除,其相关的rootf文件系统就会被删除,其容器内的数据将一并删除,为了保存相关数据,Docker提出了数据卷的概念. II. 数据卷 D ...

  8. TableLayoutPanel居中和单元格内元素居中

    在后台程序新建一个TableLayoutPanel 添加到form中,默认显示在左上角,想了很多让它居中的办法,在网上找了不少 最好的是: winform要设置控件的位置有3种: 1.控件的ancho ...

  9. S3 Browser 配置指南

    S3 Browser 相对于s3cmd是一个很方便的操作S3的图形化界面工具. 以下是配置步骤: 下载网址:http://s3browser.com/ keygen破解版: http://appdol ...

  10. DirectDraw用到的DDSURFACEDESC2

    DDSURFACEDESC2 结构定义一个需求的平面.下面的例子演示了结构的定义和标志位的设定: // Create the primary surface with one back buffer. ...