浅谈PHP的反射API

 更新时间:2017年7月6日 23:49  点击:1856
小编给大家推荐的这篇文章介绍了浅谈PHP的反射API的教程,非常实用,有兴趣的同学快来看看吧

PHP的反射API,即在PHP运行状态下,通过分析PHP程序,可以导出对象所属的类,方法,属性,参数等信息。

如何使用反射API

示例代码 Person.php

Person类,包含一个成员变量和三个成员方法

获取$student对象的方法和属性列表

ReflectionClass类报告了一个类的有关信息

输出结果为:name say __set __get

也可以用class函数,获取对象属性的关联数组的信息

通过class()函数获取类的信息

打印结果:

通过这个反射API,可以做hook实现插件功能,动态代理等。

网上找的动态代理示例

小编推荐的这篇文章介绍了Python实现 多进程导入CSV数据到 MySQL的教程,非常实用,有兴趣的同学快来看看吧

前段时间帮同事处理了一个把 CSV 数据导入到 MySQL 的需求。两个很大的 CSV 文件, 分别有 3GB、2100 万条记录和  7GB、3500 万条记录。对于这个量级的数据,用简单的单进程/单线程导入  会耗时很久,最终用了多进程的方式来实现。具体过程不赘述,记录一下几个要点:

  1. 批量插入而不是逐条插入

  2. 为了加快插入速度,先不要建索引

  3. 生产者和消费者模型,主进程读文件,多个 worker 进程执行插入

  4. 注意控制 worker 的数量,避免对 MySQL 造成太大的压力

  5. 注意处理脏数据导致的异常

  6. 原始数据是 GBK 编码,所以还要注意转换成 UTF-8

  7. 用 click 封装命令行工具

具体的代码实现如下:

 

 代码如下复制代码

#!/usr/bin/env python

# -*- coding: utf-8 -*-

 

importcodecs

importcsv

importlogging

importmultiprocessing

importos

importwarnings

 

importclick

importMySQLdb

importsqlalchemy

 

warnings.filterwarnings('ignore', category=MySQLdb.Warning)

 

# 批量插入的记录数量

BATCH=5000

 

DB_URI='mysql://root@localhost:3306/example?charset=utf8'

 

engine=sqlalchemy.create_engine(DB_URI)

 

 

defget_table_cols(table):

  sql='SELECT * FROM `{table}` LIMIT 0'.format(table=table)

  res=engine.execute(sql)

  returnres.keys()

 

 

definsert_many(table, cols, rows, cursor):

  sql='INSERT INTO `{table}` ({cols}) VALUES ({marks})'.format(

      table=table,

      cols=', '.join(cols),

      marks=', '.join(['%s']*len(cols)))

  cursor.execute(sql,*rows)

  logging.info('process %s inserted %s rows into table %s', os.getpid(),len(rows), table)

 

 

definsert_worker(table, cols, queue):

  rows=[]

  # 每个子进程创建自己的 engine 对象

  cursor=sqlalchemy.create_engine(DB_URI)

  whileTrue:

    row=queue.get()

    ifrowisNone:

      ifrows:

        insert_many(table, cols, rows, cursor)

      break

 

    rows.append(row)

    iflen(rows)==BATCH:

      insert_many(table, cols, rows, cursor)

      rows=[]

 

 

definsert_parallel(table, reader, w=10):

  cols=get_table_cols(table)

 

  # 数据队列,主进程读文件并往里写数据,worker 进程从队列读数据

  # 注意一下控制队列的大小,避免消费太慢导致堆积太多数据,占用过多内存

  queue=multiprocessing.Queue(maxsize=w*BATCH*2)

  workers=[]

  foriinrange(w):

    p=multiprocessing.Process(target=insert_worker, args=(table, cols, queue))

    p.start()

    workers.append(p)

    logging.info('starting # %s worker process, pid: %s...', i+1, p.pid)

 

  dirty_data_file='./{}_dirty_rows.csv'.format(table)

  xf=open(dirty_data_file,'w')

  writer=csv.writer(xf, delimiter=reader.dialect.delimiter)

 

  forlineinreader:

    # 记录并跳过脏数据: 键值数量不一致

    iflen(line) !=len(cols):

      writer.writerow(line)

      continue

 

    # 把 None 值替换为 'NULL'

    clean_line=[Noneifx=='NULL'elsexforxinline]

 

    # 往队列里写数据

    queue.put(tuple(clean_line))

    ifreader.line_num%500000==0:

      logging.info('put %s tasks into queue.', reader.line_num)

 

  xf.close()

 

  # 给每个 worker 发送任务结束的信号

  logging.info('send close signal to worker processes')

  foriinrange(w):

    queue.put(None)

 

  forpinworkers:

    p.join()

 

 

defconvert_file_to_utf8(f, rv_file=None):

  ifnotrv_file:

    name, ext=os.path.splitext(f)

    ifisinstance(name,unicode):

      name=name.encode('utf8')

    rv_file='{}_utf8{}'.format(name, ext)

  logging.info('start to process file %s', f)

  withopen(f) as infd:

    withopen(rv_file,'w') as outfd:

      lines=[]

      loop=0

      chunck=200000

      first_line=infd.readline().strip(codecs.BOM_UTF8).strip()+'\n'

      lines.append(first_line)

      forlineininfd:

        clean_line=line.decode('gb18030').encode('utf8')

        clean_line=clean_line.rstrip()+'\n'

        lines.append(clean_line)

        iflen(lines)==chunck:

          outfd.writelines(lines)

          lines=[]

          loop+=1

          logging.info('processed %s lines.', loop*chunck)

 

      outfd.writelines(lines)

      logging.info('processed %s lines.', loop*chunck+len(lines))

 

 

@click.group()

defcli():

  logging.basicConfig(level=logging.INFO,

            format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')

 

 

@cli.command('gbk_to_utf8')

@click.argument('f')

defconvert_gbk_to_utf8(f):

  convert_file_to_utf8(f)

 

 

@cli.command('load')

@click.option('-t','--table', required=True,help='表名')

@click.option('-i','--filename', required=True,help='输入文件')

@click.option('-w','--workers', default=10,help='worker 数量,默认 10')

defload_fac_day_pro_nos_sal_table(table, filename, workers):

  withopen(filename) as fd:

    fd.readline() # skip header

    reader=csv.reader(fd)

    insert_parallel(table, reader, w=workers)

 

 

if__name__=='__main__':

  cli()

 

小编给大家推荐的这篇文章介绍了简单谈谈PHP中的trait的教程,非常实用,有兴趣的同学快来看看吧

前言

之前的一个同事换工作,在面试被问到了 PHP 的 trait 。因为没用过, 所以没答好,我大概是用过几次的,想了想整理了以下的总结。

trait

trait 是在一些类(Class)的应该具备的特定的属性或方法,而同父级的另外一些类应该避免包含这些属性和方法情况下使用的.

当然, 这也和开发者对类的抽象能力有关, 有些抽象能力好的, 可以减少对 trait 的使用 但是这种情况应该是无法避免的 不然 trait 出现就毫无意义了.

还有一种情况, 就是使用 trait 的时候, 可以起到的约束开发者的作用, 提醒开发者注意需要在开发的过程中调用 trait 的某些属性和方法.

同事则提出了一个好问题, 接口(interface) 不也是这个作用么?

不急, 让我们先看个例子:

比如你要收集网站上各类数据, 开发了 Spider 类. Spider有个方法叫request()负责请求.

 

 代码如下 复制代码

<?phpnamespaceXWSoul\Network;

classSpider

{

 publicfunctionrequest($url)

 {

 //do sth.

 }

}

 

但是采集数据的过程中, 有些网站对蜘蛛敏感有些则不. 对于敏感的网站, 我们给出了一个使用代理的解决方案. 但是使用代理是会影响抓取速度的. 这就产生了 Spider 的子类有些需要用代理, 而能不用代理则尽量不用的情况.

于是这个时候我们新增了一个 trait Proxy:

 

 代码如下 复制代码

<?phpnamespaceXWSoul\Network;

trait Proxy

{

 

 protected$isProxy= false;

 

 publicfunctionuseProxy($proxy)

 {

 //do sth proxy setups.

 $this->isProxy = true;

 return$this;

 }

 

 publicfunctionrequest($url)

 {

 if(!$this->isProxy) {

  thrownewException("Please using proxy.");

 }

 //do sth.

 returnparent::request($url);

 }

}

 

trait 重写了 Spider 的request()方法, 限定了在没有调用代理的情况下调用会抛出异常.

回到之前的问题, trait 这样的用法和 接口(interface) 有什么区别?

接口的约束是前置的是定义初始就必须实现的, 他可以约束方法的实现却无法约束方法的调用, trait 是一种后置的调用, 他已经实现了方法,  关键的是, 他只对调用了自身的类产生约束(废话一句), 而对没有调用自身的类不产生影响(再一句废话), 同时他是可复用的, 而且没有破坏  Spider 类自身的实现增加, Spider 还是那个 Spider.

我想 trait 的用法再这里已经很有效了吧.

后话

有人可能决定 另外实现一个 request 比如叫, proxyRequst 不就完了么? 你说的好有道理&hellip;然是如果我使用了不一样的 代理具体对请求上有细节差异怎么办呢? 在代码里不停的 if if if 么? trait 如此清爽的方案 为何要放弃呢?

PHP实现批量删除效果也是很多用户会遇到的,这里文章就给大家介绍下PHP怎么实现批量删除,有些什么实现方法,感兴趣的下面就具体来看看。

前台

 

  

  

 代码如下复制代码

<!DOCTYPE html>

<html>

<head>

  <title>批量删除</title>

</head>

<body>

<scripttype="text/javascript">

  

//复选框

function checkall(all)

{

  var ck = document.getElementsByClassName("ck");

  

  if(all.checked)

  {

   for(var i=0;i<ck.length;i++)

   {

     ck[i].setAttribute("checked","checked");

   }

  }

  else

  {

   for(vari=0;i<ck.length;i++)

   {

     ck[i].removeAttribute("checked");

   }

  }

}

</script>

  

<formaction="test.php"method="post">

<tableborder="1">

  <tr><th><inputtype="checkbox"name="all"onclick="checkall(this)"/>id</th><th>名字</th></tr>

  

<!-- 此处调用显示列表函数 -->

<?phpshow() ?>

  

<tr><tdcolspan="3"><inputtype="submit"value="批量删除"></td></tr>

</table>

</form>

</body>

  

<?php 

  

//显示列表

function show()

{

  //连接数据库

  @mysql_connect('localhost','root','');

  mysql_select_db('test');

  mysql_query('set names utf8');

  

  $sql="select id,name from test";

  $res=mysql_query($sql);

  

  //循环取出数据

   while($row=mysql_fetch_row($res))

    {

     echo "<tr>

      <td>

       <inputtype='checkbox'value='{$row[0]}'name='item[]'class='ck'/>

       {$row[0]}

     </td>

      <td>{$row[1]}</td>

    </tr>";

    }

  }

?>

</html>


id名字


后台

 

 代码如下复制代码

<?php 

  

//接收post传来的数组

$arr=$_POST["item"];

  

/**

* 批量删除 

* 思路:把前台批量选择的数据放在数组里,删除该数组即可 

* @param $arr 

* @return $res 成功or失败

*/

functionbatch_del($arr)

{

  @mysql_connect('localhost','root','');

  mysql_select_db('test');

  mysql_query('set names utf8');

  

  //把数组元素组合为字符串:

  $str= implode("','",$arr);

  //in 表示多个

  $sql="delete from test where id in('{$str}')";

  $res= mysql_query($sql);

  

  if(!$res){

      echo"删除失败";

    }else{

  

      if(mysql_affected_rows()>0){

        echo"删除成功";

      }else{

        echo"没有行受到影响";  

      }

    } 

  }

  

//调用批量删除函数

  

batch_del($arr);

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助。

[!--infotagslink--]

相关文章

  • 源码分析系列之json_encode()如何转化一个对象

    这篇文章主要介绍了源码分析系列之json_encode()如何转化一个对象,对json_encode()感兴趣的同学,可以参考下...2021-04-22
  • php中去除文字内容中所有html代码

    PHP去除html、css样式、js格式的方法很多,但发现,它们基本都有一个弊端:空格往往清除不了 经过不断的研究,最终找到了一个理想的去除html包括空格css样式、js 的PHP函数。...2013-08-02
  • index.php怎么打开?如何打开index.php?

    index.php怎么打开?初学者可能不知道如何打开index.php,不会的同学可以参考一下本篇教程 打开编辑:右键->打开方式->经文本方式打开打开运行:首先你要有个支持运行PH...2017-07-06
  • WebStorm无法正确识别Vue3组合式API的解决方案

    这篇文章主要介绍了WebStorm无法正确识别Vue3组合式API的解决方案,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...2021-02-18
  • 浅谈vue2的$refs在vue3组合式API中的替代方法

    这篇文章主要介绍了浅谈vue2的$refs在vue3组合式API中的替代方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-18
  • PHP中func_get_args(),func_get_arg(),func_num_args()的区别

    复制代码 代码如下:<?php function jb51(){ print_r(func_get_args()); echo "<br>"; echo func_get_arg(1); echo "<br>"; echo func_num_args(); } jb51("www","j...2013-10-04
  • PHP编程 SSO详细介绍及简单实例

    这篇文章主要介绍了PHP编程 SSO详细介绍及简单实例的相关资料,这里介绍了三种模式跨子域单点登陆、完全跨单点域登陆、站群共享身份认证,需要的朋友可以参考下...2017-01-25
  • PHP实现创建以太坊钱包转账等功能

    这篇文章主要介绍了PHP实现创建以太坊钱包转账等功能,对以太坊感兴趣的同学,可以参考下...2021-04-20
  • 如何使用 JavaScript 操作浏览器历史记录 API

    这篇文章主要介绍了如何使用 JavaScript 操作浏览器历史记录 API,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下...2020-11-24
  • php微信公众账号开发之五个坑(二)

    这篇文章主要为大家详细介绍了php微信公众账号开发之五个坑,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-02
  • 理解JavaScript中worker事件api

    这篇文章主要帮助大家理解JavaScript中worker事件api,对worker事件api有一个深刻了解,感兴趣的小伙伴们可以参考一下...2015-12-27
  • 如何设计一个安全的API接口详解

    在日常开发中,总会接触到各种接口,前后端数据传输接口,第三方业务平台接口,下面这篇文章主要给大家介绍了关于如何设计一个安全的API接口的相关资料,需要的朋友可以参考下...2021-08-12
  • PHP如何通过date() 函数格式化显示时间

    这篇文章主要介绍了PHP如何通过date() 函数格式化显示时间,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-11-13
  • C# Windows API应用之基于GetDesktopWindow获得桌面所有窗口句柄的方法

    这篇文章主要介绍了C# Windows API应用之基于GetDesktopWindow获得桌面所有窗口句柄的方法,结合实例形式分析了GetDesktopWindow函数用于获取窗口句柄的具体使用方法与相关注意事项,需要的朋友可以参考下...2020-06-25
  • ThinkPHP使用心得分享-ThinkPHP + Ajax 实现2级联动下拉菜单

    首先是数据库的设计。分类表叫cate.我做的是分类数据的二级联动,数据需要的字段有:id,name(中文名),pid(父id). 父id的设置: 若数据没有上一级,则父id为0,若有上级,则父id为上一级的id。数据库有内容后,就可以开始写代码,进...2014-05-31
  • vue设置全局访问接口API地址操作

    这篇文章主要介绍了vue设置全局访问接口API地址操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-14
  • Vue常用API、高级API的相关总结

    这篇文章主要介绍了Vue常用API、高级API的相关总结,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...2021-02-04
  • Swift 中如何使用 Option Pattern 改善可选项的 API 设计

    这篇文章主要介绍了Swift 中如何使用 Option Pattern 改善可选项的 API 设计,帮助大家更好的进行ios开发,感兴趣的朋友可以了解下...2020-10-23
  • 浅谈VUE uni-app 常用API

    这篇文章主要介绍了uni-app 常用API,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-10-20
  • golang与php实现计算两个经纬度之间距离的方法

    这篇文章主要介绍了golang与php实现计算两个经纬度之间距离的方法,结合实例形式对比分析了Go语言与php进行经纬度计算的相关数学运算技巧,需要的朋友可以参考下...2016-07-29